diff --git a/build_ui.sh b/build_ui.sh new file mode 100755 index 0000000..f9351b9 --- /dev/null +++ b/build_ui.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +/usr/bin/pyuic5 ui/mainwindow.ui > src/nailab/ui_gen/mainwindow.py +/usr/bin/pyuic5 ui/strategywidget.ui > src/nailab/ui_gen/strategywidget.py diff --git a/src/nailab/nailab.py b/src/nailab/nailab.py index 9bd4248..af7b04a 100644 --- a/src/nailab/nailab.py +++ b/src/nailab/nailab.py @@ -1,21 +1,19 @@ -import gi -gi.require_version('Gtk', '3.0') -gi.require_version('GtkSource', '3.0') -from gi.repository import Gtk, GObject -from gi.repository import GtkSource - -from nailab.ui.applicationwindow import ApplicationWindow +import sys +from PyQt5.QtWidgets import QApplication +from PyQt5 import QtCore +from ui.mainwindow import MainWindow def main(): - GObject.type_register(GtkSource.View) - - builder = Gtk.Builder() - builder.add_from_file('ui/nailab.glade') - - ApplicationWindow(builder) + QApplication.setOrganizationDomain("kasan.ws") + QApplication.setOrganizationName("K.A.S.A.N.") + QApplication.setApplicationName("nailab") + app = QApplication(sys.argv) - Gtk.main() + wnd = MainWindow() + wnd.show() + + return app.exec_() if __name__ == '__main__': main() diff --git a/src/nailab/ui/applicationwindow.py b/src/nailab/ui/applicationwindow.py deleted file mode 100644 index b964320..0000000 --- a/src/nailab/ui/applicationwindow.py +++ /dev/null @@ -1,108 +0,0 @@ - -from gi.repository import Gtk, GtkSource - -from nailab.data.datasource import DataSource -from nailab.data.datasourcemanager import DataSourceManager -from nailab.execution.executor import Executor -from nailab.templates.new_strategy import new_strategy_template - -from .resultstable import ResultsTableWidget -from .tabmanager import TabManager - -class ApplicationWindow: - - def __init__(self, builder): - self.window = builder.get_object('ApplicationWindow') - self.tab_manager = TabManager(builder.get_object('sourceNotebook')) - - self._init_tv_datasource(builder) - - handlers = { - 'on_ApplicationWindow_delete_event' : Gtk.main_quit, - 'on_menuNew' : self.new_file, - 'on_OpenFile' : self.open_file, - 'on_menuSave' : self.save_file, - 'on_menuSaveAs' : self.save_file_as, - 'on_menuQuit' : Gtk.main_quit, - 'on_StrategyExecute' : self.strategy_execute - } - - builder.connect_signals(handlers) - self.window.show_all() - - def new_file(self, arg): - self.tab_manager.new_from_template(new_strategy_template) - - def open_file(self, arg): - dlg = Gtk.FileChooserDialog('Open file', self.window, Gtk.FileChooserAction.OPEN, - (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, - Gtk.STOCK_OPEN, Gtk.ResponseType.OK)) - result = dlg.run() - - if result == Gtk.ResponseType.OK: - self.tab_manager.new_tab(dlg.get_filename()) - - dlg.destroy() - - def save_file(self, arg): - self.tab_manager.save_current() - - def save_file_as(self, arg): - dlg = Gtk.FileChooserDialog('Save file', self.window, Gtk.FileChooserAction.SAVE, - (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, - Gtk.STOCK_SAVE, Gtk.ResponseType.OK)) - result = dlg.run() - - if result == Gtk.ResponseType.OK: - self.tab_manager.save_current_as(dlg.get_filename()) - - dlg.destroy() - - def strategy_execute(self, arg): - sel = self.tv_datasources.get_selection() - model, rows = sel.get_selected_rows() - - feeds = [] - for row in rows: - (feed_id, source_name) = self.datasources_store.get(self.datasources_store.get_iter(row), 0, 1) - source = self.datasourcemanager.get_source(source_name) - if source is not None: - feed = source.get_feed(feed_id) - feeds.append(feed) - - e = Executor() - (result, trades) = e.execute_from_file(self.tab_manager.get_current_source_path(), feeds) - - self._add_results_page(result, trades) - - def _add_results_page(self, results, trades): - res_widget = ResultsTableWidget() - res_widget.set_results(results, trades) - res_widget.show_all() - self.tab_manager.new_misc_tab(res_widget) - - def _init_tv_datasource(self, builder): - self.datasourcemanager = DataSourceManager() - self.datasourcemanager.load_sources() - - tv_datasources = builder.get_object('tv_datasources') - self.tv_datasources = tv_datasources - - self.datasources_store = Gtk.TreeStore(str, str) - for source in self.datasourcemanager.all_sources(): - treeiter = self.datasources_store.append(None, (source.name, source.name)) - for feed in source.available_feeds(): - self.datasources_store.append(treeiter, (feed, source.name)) - - - rendererText = Gtk.CellRendererText() - column = Gtk.TreeViewColumn('Datasources', rendererText, text=0) - tv_datasources.append_column(column) - - tv_datasources.set_model(self.datasources_store) - - sel = tv_datasources.get_selection() - sel.set_mode(Gtk.SelectionMode.MULTIPLE) - - - diff --git a/src/nailab/ui/equitygraph.py b/src/nailab/ui/equitygraph.py deleted file mode 100644 index d306b51..0000000 --- a/src/nailab/ui/equitygraph.py +++ /dev/null @@ -1,39 +0,0 @@ - -from gi.repository import Gtk - -class EquityGraph(Gtk.Misc): - - def __init__(self): - super().__init__() - self.trades = [] - self.cumulative_pnl = [] - - def do_draw(self, cr): - bg_color = self.get_style_context().get_background_color(Gtk.StateFlags.NORMAL) - cr.set_source_rgba(*list(bg_color)) - cr.paint() - - allocation = self.get_allocation() - if len(self.cumulative_pnl) > 0: - fg_color = self.get_style_context().get_color(Gtk.StateFlags.NORMAL) - cr.set_source_rgba(*list(fg_color)); - cr.set_line_width(2) - - min_equity = min(self.cumulative_pnl) - max_equity = max(self.cumulative_pnl) - - kx = allocation.width / len(self.cumulative_pnl) - ky = 0.8 * allocation.height / (max_equity - min_equity) - - cr.move_to(0, allocation.height * 0.9 - (self.cumulative_pnl[0] - min_equity) * ky) - for i, x in enumerate(self.cumulative_pnl[1:]): - cr.line_to((i + 1) * kx, allocation.height * 0.9 - (x - min_equity) * ky) - cr.stroke() - - def set_trades(self, trades): - self.trades = trades - s = 0 - self.cumulative_pnl = [] - for trade in trades: - s += trade['pnl'] - self.cumulative_pnl.append(s) diff --git a/src/nailab/ui/mainwindow.py b/src/nailab/ui/mainwindow.py new file mode 100644 index 0000000..255d419 --- /dev/null +++ b/src/nailab/ui/mainwindow.py @@ -0,0 +1,65 @@ + +import os +import importlib +import importlib.util +import inspect + +from execution.executor import Executor +from naiback.data.feeds.genericcsvfeed import GenericCSVFeed + +from PyQt5 import QtCore, QtGui, QtWidgets +from PyQt5.Qsci import * + +from ui_gen.mainwindow import Ui_MainWindow +from ui.strategywidget import StrategyWidget + +from naiback.strategy import Strategy + +def is_strategy(obj): + return inspect.isclass(obj) and Strategy in inspect.getmro(obj)[1:] + +class MainWindow(QtWidgets.QMainWindow): + + def __init__(self, parent=None): + super().__init__(parent) + + self.sources = [] + + self.ui = Ui_MainWindow() + self.ui.setupUi(self) + + def openTrades(self): + pass + + def newStrategy(self): + self._makeEditor() + + def openStrategy(self): + settings = QtCore.QSettings() + filename = QtWidgets.QFileDialog.getOpenFileName(self, self.tr("Select a file..."), settings.value("open_strategy_path"), self.tr("Python (*.py);;All (*.*, *)"))[0] + if filename != "": + with open(filename, "r") as f: + self._makeEditor(filename, os.path.basename(filename), f.read()) + settings.setValue("open_strategy_path", os.path.dirname(filename)) + + def executeStrategy(self): + source_file = self.sources[self.ui.tabs.currentIndex()] + executor = Executor() + result = executor.execute_from_file(source_file, []) + print(result) + +# spec = importlib.util.spec_from_file_location("m", source_file) +# mod = importlib.util.module_from_spec(spec) +# spec.loader.exec_module(mod) +# classes = inspect.getmembers(mod, is_strategy) +# strategy_class = classes[0][0] + + + def tabCloseRequested(self, tab_index): + del self.sources[tab_index] + self.ui.tabs.removeTab(tab_index) + + def _makeEditor(self, source_file=None, tab_name="Untitled", content=None): + editor = StrategyWidget(self, content) + self.sources.append(source_file) + self.ui.tabs.addTab(editor, tab_name) diff --git a/src/nailab/ui/resultstable.py b/src/nailab/ui/resultstable.py deleted file mode 100644 index b5b705e..0000000 --- a/src/nailab/ui/resultstable.py +++ /dev/null @@ -1,59 +0,0 @@ - -from gi.repository import Gtk - -from prettytable import PrettyTable - -from .equitygraph import EquityGraph - -def render_float(a): - return "{:.3f}".format(a) - -def render_ratio(a, b): - if b != 0: - return a / b - else: - return "∞" - -class ResultsTableWidget(Gtk.Notebook): - - def __init__(self): - super().__init__() - - self.set_tab_pos(Gtk.PositionType.LEFT) - - self.buffer = Gtk.TextBuffer() - self.text_result = Gtk.TextView() - self.text_result.set_buffer(self.buffer) - self.append_page(self.text_result, Gtk.Label('Statistics')) - - self.equity_graph = EquityGraph() - self.append_page(self.equity_graph, Gtk.Label('Equity')) - - style_ctx = self.text_result.get_style_context() - self.provider = Gtk.CssProvider() - self.provider.load_from_data(b'GtkTextView { font-family: "Monospace"; }') - style_ctx.add_provider(self.provider, Gtk.STYLE_PROVIDER_PRIORITY_USER) - - def set_results(self, results, trades): - self.buffer.set_text(self.generate_plain_text(results)) - self.equity_graph.set_trades(trades) - - def generate_plain_text(self, stats): - - table = PrettyTable() - table.field_names = ["", "All positions", "Long only", "Short only"] - table.add_row(["Net profit", render_float(stats['all']['net_profit']), render_float(stats['long']['net_profit']), render_float(stats['short']['net_profit'])]) - table.add_row(["Bars in trade", stats['all']['bars_in_trade'], stats['long']['bars_in_trade'], stats['short']['bars_in_trade']]) - table.add_row(["Profit per bar", render_float(stats['all']['profit_per_bar']), render_float(stats['long']['profit_per_bar']), render_float(stats['short']['profit_per_bar'])]) - table.add_row(["Number of trades", stats['all']['number_of_trades'], stats['long']['number_of_trades'], stats['short']['number_of_trades']]) - table.add_row(["Avg. profit", render_float(stats['all']['avg']), render_float(stats['long']['avg']), render_float(stats['short']['avg'])]) - table.add_row(["Avg. profit, %", render_float(stats['all']['avg_percentage']), render_float(stats['long']['avg_percentage']), render_float(stats['short']['avg_percentage'])]) - table.add_row(["Avg. bars in trade", render_float(stats['all']['avg_bars']), render_float(stats['long']['avg_bars']), render_float(stats['short']['avg_bars'])]) - table.add_row(["Winning trades", stats['all']['won'], stats['long']['won'], stats['short']['won']]) - table.add_row(["Gross profit", render_float(stats['all']['total_won']), render_float(stats['long']['total_won']), render_float(stats['short']['total_won'])]) - table.add_row(["Losing trades", stats['all']['lost'], stats['long']['lost'], stats['short']['lost']]) - table.add_row(["Gross loss", render_float(stats['all']['total_lost']), render_float(stats['long']['total_lost']), render_float(stats['short']['total_lost'])]) - table.add_row(["Profit factor", render_float(stats['all']['profit_factor']), render_float(stats['long']['profit_factor']), render_float(stats['short']['profit_factor'])]) - - return table.get_string() - diff --git a/src/nailab/ui/sourceviewcontroller.py b/src/nailab/ui/sourceviewcontroller.py deleted file mode 100644 index 2a660f7..0000000 --- a/src/nailab/ui/sourceviewcontroller.py +++ /dev/null @@ -1,13 +0,0 @@ - -class SourceViewController: - - def __init__(self, sourceview): - self.sourceview = sourceview - - def set_source_text(self, text): - self.sourceview.get_buffer().set_text(text) - - def get_source_text(self): - buf = self.sourceview.get_buffer() - return buf.get_text(buf.get_start_iter(), buf.get_end_iter(), True) - diff --git a/src/nailab/ui/strategywidget.py b/src/nailab/ui/strategywidget.py new file mode 100644 index 0000000..dcfacde --- /dev/null +++ b/src/nailab/ui/strategywidget.py @@ -0,0 +1,28 @@ + +from PyQt5 import QtCore, QtGui, QtWidgets +from PyQt5.Qsci import * + +from ui_gen.strategywidget import Ui_StrategyWidget + +class StrategyWidget(QtWidgets.QWidget): + + def __init__(self, parent=None, content=None): + super().__init__(parent) + + self.ui = Ui_StrategyWidget() + self.ui.setupUi(self) + + self.ui.splitter.setSizes([20, 80]) + self.ui.splitter.setStretchFactor(0, 1) + self.ui.splitter.setStretchFactor(1, 1) + + font = QtGui.QFont("DejaVu Sans Mono") + font.setPointSize(10) + self.ui.editor.setFont(font) + if content is not None: + self.ui.editor.setText(content) + + lexer = QsciLexerPython() + lexer.setFont(font) + self.ui.editor.setLexer(lexer) + self.ui.editor.setUtf8(True) diff --git a/src/nailab/ui/tabmanager.py b/src/nailab/ui/tabmanager.py deleted file mode 100644 index f69cd47..0000000 --- a/src/nailab/ui/tabmanager.py +++ /dev/null @@ -1,143 +0,0 @@ - -from gi.repository import GObject, Gtk, GtkSource, Pango - -from .sourceviewcontroller import SourceViewController - -class TabManager(GObject.Object): - - def __init__(self, notebook): - super().__init__() - self.notebook = notebook - self.widgets = {} - self.source_controllers = {} - self.id_counter = 1 - self.source_paths = {} - - def new_misc_tab(self, widget): - tab_id = self._next_tab_id() - self.widgets[tab_id] = widget - header = Gtk.HBox() - title_label = Gtk.Label('Result') - image = Gtk.Image() - image.set_from_stock(Gtk.STOCK_CLOSE, Gtk.IconSize.MENU) - close_button = Gtk.Button() - close_button.set_image(image) - close_button.set_relief(Gtk.ReliefStyle.NONE) - close_button.connect('clicked', self.close_cb, tab_id) - - header.pack_start(title_label, - expand=True, fill=True, padding=0) - header.pack_end(close_button, - expand=False, fill=False, padding=0) - header.show_all() - - index = self.notebook.append_page(widget, header) - self.notebook.set_current_page(index) - - def _read_source_file(self, source_file): - if source_file is not None: - with open(source_file, 'r') as f: - return f.read() - else: - return None - - - def new_tab(self, source_file): - tab_id = self._next_tab_id() - (sv, sv_controller) = self._init_sourceeditor() - - source = self._read_source_file(source_file) - if source is not None: - sv_controller.set_source_text(source) - - self.source_paths[tab_id] = source_file - self.source_controllers[tab_id] = sv_controller - self.widgets[tab_id] = sv - sv.show_all() - header = Gtk.HBox() - title_label = Gtk.Label(source_file) - image = Gtk.Image() - image.set_from_stock(Gtk.STOCK_CLOSE, Gtk.IconSize.MENU) - close_button = Gtk.Button() - close_button.set_image(image) - close_button.set_relief(Gtk.ReliefStyle.NONE) - close_button.connect('clicked', self.close_cb, tab_id) - - header.pack_start(title_label, - expand=True, fill=True, padding=0) - header.pack_end(close_button, - expand=False, fill=False, padding=0) - header.show_all() - index = self.notebook.append_page(sv, header) - self.notebook.set_current_page(index) - return tab_id - - def close_cb(self, arg, tab_id): - index = self._widget_num_by_tab_id(tab_id) - self.notebook.remove_page(index) - del self.widgets[tab_id] - if tab_id in self.source_paths: - del self.source_paths[tab_id] - if tab_id in self.source_controllers: - del self.source_controllers[tab_id] - - def get_current_source_path(self): - index = self.notebook.get_current_page() - w = self.notebook.get_nth_page(index) - for k, v in self.widgets.items(): - if v == w: - return self.source_paths[k] - - return None - - def new_from_template(self, template): - tab_id = self.new_tab(None) - self.source_controllers[tab_id].set_source_text(template) - - def save_current(self): - index = self.notebook.get_current_page() - w = self.notebook.get_nth_page(index) - for k, v in self.widgets.items(): - if v == w: - text = self.source_controllers[k].get_source_text() - with open(self.source_paths[k], 'w') as f: - f.write(text) - - def save_current_as(self, path): - index = self.notebook.get_current_page() - w = self.notebook.get_nth_page(index) - for k, v in self.widgets.items(): - if v == w: - text = self.source_controllers[k].get_source_text() - with open(path, 'w') as f: - f.write(text) - - def _init_sourceeditor(self): - scroll = Gtk.ScrolledWindow() - manager = GtkSource.LanguageManager() - buf = GtkSource.Buffer() - buf.set_language(manager.get_language('python')) - sv = GtkSource.View() - sv.set_buffer(buf) - sv.set_monospace(True) - - style_ctx = sv.get_style_context() - self.provider = Gtk.CssProvider() - self.provider.load_from_data(b'GtkSourceView { font-family: "Monospace"; }') - style_ctx.add_provider(self.provider, Gtk.STYLE_PROVIDER_PRIORITY_USER) - - sourceviewcontroller = SourceViewController(sv) - scroll.add(sv) - scroll.show() - - return (scroll, sourceviewcontroller) - - def _widget_num_by_tab_id(self, tab_id): - for i in range(0, self.notebook.get_n_pages()): - if self.widgets[tab_id] == self.notebook.get_nth_page(i): - return i - return None - - def _next_tab_id(self): - self.id_counter += 1 - return self.id_counter diff --git a/src/nailab/ui_gen/__init__.py b/src/nailab/ui_gen/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/nailab/ui_gen/mainwindow.py b/src/nailab/ui_gen/mainwindow.py new file mode 100644 index 0000000..796dae5 --- /dev/null +++ b/src/nailab/ui_gen/mainwindow.py @@ -0,0 +1,67 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'ui/mainwindow.ui' +# +# Created by: PyQt5 UI code generator 5.5.1 +# +# WARNING! All changes made in this file will be lost! + +from PyQt5 import QtCore, QtGui, QtWidgets + +class Ui_MainWindow(object): + def setupUi(self, MainWindow): + MainWindow.setObjectName("MainWindow") + MainWindow.resize(1050, 712) + self.centralwidget = QtWidgets.QWidget(MainWindow) + self.centralwidget.setObjectName("centralwidget") + self.gridLayout = QtWidgets.QGridLayout(self.centralwidget) + self.gridLayout.setContentsMargins(3, 3, 3, 3) + self.gridLayout.setObjectName("gridLayout") + self.tabs = QtWidgets.QTabWidget(self.centralwidget) + self.tabs.setTabsClosable(True) + self.tabs.setObjectName("tabs") + self.gridLayout.addWidget(self.tabs, 0, 0, 1, 1) + MainWindow.setCentralWidget(self.centralwidget) + self.menubar = QtWidgets.QMenuBar(MainWindow) + self.menubar.setGeometry(QtCore.QRect(0, 0, 1050, 23)) + self.menubar.setObjectName("menubar") + self.menuFile = QtWidgets.QMenu(self.menubar) + self.menuFile.setObjectName("menuFile") + self.menuBacktest = QtWidgets.QMenu(self.menubar) + self.menuBacktest.setObjectName("menuBacktest") + MainWindow.setMenuBar(self.menubar) + self.statusbar = QtWidgets.QStatusBar(MainWindow) + self.statusbar.setObjectName("statusbar") + MainWindow.setStatusBar(self.statusbar) + self.actionOpenTrades = QtWidgets.QAction(MainWindow) + self.actionOpenTrades.setObjectName("actionOpenTrades") + self.actionNew_strategy = QtWidgets.QAction(MainWindow) + self.actionNew_strategy.setObjectName("actionNew_strategy") + self.actionOpen_strategy = QtWidgets.QAction(MainWindow) + self.actionOpen_strategy.setObjectName("actionOpen_strategy") + self.actionExecute = QtWidgets.QAction(MainWindow) + self.actionExecute.setObjectName("actionExecute") + self.menuFile.addAction(self.actionNew_strategy) + self.menuFile.addAction(self.actionOpen_strategy) + self.menuBacktest.addAction(self.actionExecute) + self.menubar.addAction(self.menuFile.menuAction()) + self.menubar.addAction(self.menuBacktest.menuAction()) + + self.retranslateUi(MainWindow) + self.tabs.setCurrentIndex(-1) + self.actionOpen_strategy.triggered.connect(MainWindow.openStrategy) + self.tabs.tabCloseRequested['int'].connect(MainWindow.tabCloseRequested) + self.actionNew_strategy.triggered.connect(MainWindow.newStrategy) + self.actionExecute.triggered.connect(MainWindow.executeStrategy) + QtCore.QMetaObject.connectSlotsByName(MainWindow) + + def retranslateUi(self, MainWindow): + _translate = QtCore.QCoreApplication.translate + MainWindow.setWindowTitle(_translate("MainWindow", "Nailab")) + self.menuFile.setTitle(_translate("MainWindow", "File")) + self.menuBacktest.setTitle(_translate("MainWindow", "Backtest")) + self.actionOpenTrades.setText(_translate("MainWindow", "Open...")) + self.actionNew_strategy.setText(_translate("MainWindow", "New strategy")) + self.actionOpen_strategy.setText(_translate("MainWindow", "Open strategy")) + self.actionExecute.setText(_translate("MainWindow", "Execute")) + diff --git a/src/nailab/ui_gen/strategywidget.py b/src/nailab/ui_gen/strategywidget.py new file mode 100644 index 0000000..7f50101 --- /dev/null +++ b/src/nailab/ui_gen/strategywidget.py @@ -0,0 +1,50 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'ui/strategywidget.ui' +# +# Created by: PyQt5 UI code generator 5.5.1 +# +# WARNING! All changes made in this file will be lost! + +from PyQt5 import QtCore, QtGui, QtWidgets + +class Ui_StrategyWidget(object): + def setupUi(self, StrategyWidget): + StrategyWidget.setObjectName("StrategyWidget") + StrategyWidget.resize(839, 464) + self.gridLayout = QtWidgets.QGridLayout(StrategyWidget) + self.gridLayout.setObjectName("gridLayout") + self.splitter = QtWidgets.QSplitter(StrategyWidget) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Preferred) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.splitter.sizePolicy().hasHeightForWidth()) + self.splitter.setSizePolicy(sizePolicy) + self.splitter.setOrientation(QtCore.Qt.Horizontal) + self.splitter.setObjectName("splitter") + self.treeWidget = QtWidgets.QTreeWidget(self.splitter) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Expanding) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.treeWidget.sizePolicy().hasHeightForWidth()) + self.treeWidget.setSizePolicy(sizePolicy) + self.treeWidget.setObjectName("treeWidget") + self.treeWidget.headerItem().setText(0, "1") + self.editor = Qsci.QsciScintilla(self.splitter) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Preferred) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.editor.sizePolicy().hasHeightForWidth()) + self.editor.setSizePolicy(sizePolicy) + self.editor.setMinimumSize(QtCore.QSize(300, 0)) + self.editor.setObjectName("editor") + self.gridLayout.addWidget(self.splitter, 0, 0, 1, 1) + + self.retranslateUi(StrategyWidget) + QtCore.QMetaObject.connectSlotsByName(StrategyWidget) + + def retranslateUi(self, StrategyWidget): + _translate = QtCore.QCoreApplication.translate + StrategyWidget.setWindowTitle(_translate("StrategyWidget", "Form")) + +from PyQt5 import Qsci diff --git a/ui/mainwindow.ui b/ui/mainwindow.ui new file mode 100644 index 0000000..8a95fc9 --- /dev/null +++ b/ui/mainwindow.ui @@ -0,0 +1,163 @@ + + + MainWindow + + + + 0 + 0 + 1050 + 712 + + + + Nailab + + + + + 3 + + + 3 + + + 3 + + + 3 + + + + + -1 + + + true + + + + + + + + + 0 + 0 + 1050 + 23 + + + + + File + + + + + + + Backtest + + + + + + + + + + Open... + + + + + New strategy + + + + + Open strategy + + + + + Execute + + + + + + + actionOpen_strategy + triggered() + MainWindow + openStrategy() + + + -1 + -1 + + + 524 + 355 + + + + + tabs + tabCloseRequested(int) + MainWindow + tabCloseRequested(int) + + + 481 + 335 + + + 1049 + 99 + + + + + actionNew_strategy + triggered() + MainWindow + newStrategy() + + + -1 + -1 + + + 524 + 355 + + + + + actionExecute + triggered() + MainWindow + executeStrategy() + + + -1 + -1 + + + 524 + 355 + + + + + + openTrades() + openStrategy() + tabCloseRequested(int) + newStrategy() + executeStrategy() + + diff --git a/ui/nailab.glade b/ui/nailab.glade deleted file mode 100644 index 11e5d65..0000000 --- a/ui/nailab.glade +++ /dev/null @@ -1,246 +0,0 @@ - - - - - - True - False - gtk-missing-image - - - - 1024 - 768 - False - 2 - - - - True - False - 0 - none - - - True - True - 200 - True - - - True - True - in - - - True - True - natural - natural - model_dataSources - True - both - - - - - - - - False - True - - - - - True - True - - - - - - - - - - - - - - - - - - - - - True - True - - - - - - - True - False - - - True - False - _Файл - True - - - True - False - - - gtk-new - True - False - True - True - - - - - - gtk-open - True - False - True - True - - - - - - gtk-save - True - False - True - True - - - - - - gtk-save-as - True - False - True - True - - - - - - True - False - - - - - gtk-quit - True - False - True - True - - - - - - - - - - True - False - _Правка - True - - - True - False - - - gtk-cut - True - False - True - True - - - - - gtk-copy - True - False - True - True - - - - - gtk-paste - True - False - True - True - - - - - gtk-delete - True - False - True - True - - - - - - - - - True - False - _Вид - True - - - - - True - False - Strategy - True - - - True - False - - - Execute - - True - False - image1 - False - - - - - - - - - - - - - diff --git a/ui/strategywidget.ui b/ui/strategywidget.ui new file mode 100644 index 0000000..906a668 --- /dev/null +++ b/ui/strategywidget.ui @@ -0,0 +1,69 @@ + + + StrategyWidget + + + + 0 + 0 + 839 + 464 + + + + Form + + + + + + + 0 + 0 + + + + Qt::Horizontal + + + + + 0 + 0 + + + + + 1 + + + + + + + 0 + 0 + + + + + 300 + 0 + + + + + + + + + + QsciScintilla + QWidget +
qsciscintilla.h
+ 1 +
+
+ + +