You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
128 lines
5.1 KiB
128 lines
5.1 KiB
''' |
|
''' |
|
|
|
from PyQt5.QtWidgets import QMainWindow, QTreeWidgetItem |
|
|
|
from .ui_mainwindow import Ui_MainWindow |
|
from solver.solver import Solver |
|
from data.series import Series |
|
from data.signal import PriceComparisonSignalGenerator, RsiSignalGenerator,\ |
|
AtrSignalGenerator, DayOfWeekSignalGenerator, CrtdrSignalGenerator,\ |
|
AtrDeltaSignalGenerator, SmaSignalGenerator, DayOfMonthSignalGenerator,\ |
|
CciSignalGenerator, BbandsSignalGenerator, PivotPointsSignalGenerator,\ |
|
StochasticSignalGenerator, IntradayBarNumberSignalGenerator,\ |
|
GainPercentrankSignalGenerator |
|
from PyQt5.Qt import Qt, QFileDialog, QThread, Q_ARG, QMetaObject |
|
from PyQt5 import QtCore |
|
|
|
import pyqtgraph |
|
import numpy |
|
from backtrader import strategies |
|
|
|
class MainWindow(QMainWindow, Ui_MainWindow): |
|
''' |
|
''' |
|
|
|
def __init__(self, parent=None): |
|
''' |
|
Constructor |
|
''' |
|
super().__init__(parent) |
|
self.setupUi(self) |
|
self.work_thread = QThread() |
|
self.work_thread.start() |
|
|
|
self.timer = QtCore.QTimer(self) |
|
self.timer.timeout.connect(self.speed) |
|
|
|
|
|
def browse(self): |
|
fname = QFileDialog.getOpenFileName(self, 'Open file') |
|
if fname[0] != '': |
|
self.e_filename.setText(fname[0]) |
|
|
|
def go(self): |
|
self.tw_strategies.clear() |
|
self.series = Series() |
|
self.series.load_from_finam_csv(self.e_filename.text()) |
|
self.solver = Solver(self.series) |
|
self.solver.add_generator(PriceComparisonSignalGenerator()) |
|
self.solver.add_generator(RsiSignalGenerator()) |
|
self.solver.add_generator(AtrSignalGenerator()) |
|
self.solver.add_generator(AtrDeltaSignalGenerator()) |
|
self.solver.add_generator(DayOfWeekSignalGenerator()) |
|
self.solver.add_generator(DayOfMonthSignalGenerator()) |
|
self.solver.add_generator(SmaSignalGenerator()) |
|
self.solver.add_generator(CrtdrSignalGenerator()) |
|
self.solver.add_generator(CciSignalGenerator()) |
|
self.solver.add_generator(BbandsSignalGenerator()) |
|
self.solver.add_generator(PivotPointsSignalGenerator()) |
|
self.solver.add_generator(StochasticSignalGenerator()) |
|
self.solver.add_generator(IntradayBarNumberSignalGenerator(60)) |
|
self.solver.add_generator(GainPercentrankSignalGenerator()) |
|
|
|
self.timer.start(10000.0) |
|
|
|
params = { 'num_strategies' : self.sb_strategiesNum.value(), |
|
'max_hold_bars' : self.sb_maxHoldBars.value() } |
|
if self.cb_minTradesFilter.isChecked(): |
|
params['min_trades'] = self.sb_minTrades.value() |
|
|
|
if self.cb_minWinRate.isChecked(): |
|
params['min_win_rate'] = self.sb_minWinRate.value() |
|
if self.cb_minSharpe.isChecked(): |
|
params['min_sharpe'] = self.sb_minSharpe.value() |
|
|
|
if self.rb_long.isChecked(): |
|
params['direction'] = 'long' |
|
else: |
|
params['direction'] = 'short' |
|
|
|
if self.cb_stopLoss.isChecked(): |
|
params['stop_loss'] = self.sb_stopLoss.value() / 100.; |
|
if self.cb_takeProfit.isChecked(): |
|
params['take_profit'] = self.sb_takeProfit.value() / 100.; |
|
|
|
self.solver.done.connect(self.done) |
|
self.solver.progress.connect(self.progress) |
|
|
|
self.solver.moveToThread(self.work_thread) |
|
QMetaObject.invokeMethod(self.solver, 'solve', Q_ARG(dict, params)) |
|
#results = self.solver.solve(params) |
|
|
|
def done(self, results): |
|
for result in results: |
|
item = QTreeWidgetItem(self.tw_strategies) |
|
item.setText(0, result['display_name']) |
|
item.setText(1, str(result['trades_number'])) |
|
item.setText(2, "{:.4f}".format(result['total_pnl'])) |
|
item.setText(3, "{:.2f}".format(result['profit_factor'])) |
|
item.setText(4, "{:.2f}".format(result['sharpe'])) |
|
item.setText(5, "{:.2f}%".format(result['avg_percentage'])) |
|
item.setText(6, "{:.2f}%".format(result['win_percentage'])) |
|
item.setData(0, Qt.UserRole + 1, result) |
|
|
|
for i in range(0, 7): |
|
self.tw_strategies.resizeColumnToContents(i) |
|
|
|
def progress(self, current, total): |
|
if current < total: |
|
self.pb_progress.setValue(float(current) / total * 100) |
|
else: |
|
self.pb_progress.setValue(100) |
|
|
|
def speed(self): |
|
print(self.solver.counter) |
|
self.statusbar.showMessage("{:.2f} sps, {:d} total ({:.2f}% yield)".format(self.solver.counter / 10., self.solver.total_counter, 100. * float(self.tw_strategies.topLevelItemCount()) / self.solver.total_counter)) |
|
self.solver.counter = 0 |
|
|
|
|
|
def strategyClicked(self, item, column): |
|
result = item.data(0, Qt.UserRole + 1) |
|
pnl = numpy.cumsum([trade.pnl() for trade in result['trades']]) |
|
xs = [trade.entry_bar for trade in result['trades']] |
|
pyqtgraph.plot(xs, pnl) |
|
|
|
#for trade in result['trades']: |
|
# print(trade.entry_bar, trade.entry_price, trade.exit_price) |
|
|
|
|