Browse Source

Some updates

master
Denis Tereshkin 5 years ago
parent
commit
fb364a5f37
  1. 20
      build_ui.sh
  2. 3
      src/nailab/data/datasourcemanager.py
  3. 44
      src/nailab/data/yahoocsvfolderdatasource.py
  4. 10
      src/nailab/execution/executor.py
  5. 27
      src/nailab/execution/portfolioexecutor.py
  6. 249
      src/nailab/nailab_rc.py
  7. 7
      src/nailab/ui/mainwindow.py
  8. 6
      src/nailab/ui/newdatasourcedialog.py
  9. 26
      src/nailab/ui/settingswindow.py
  10. 117
      src/nailab/ui/statisticwidget.py
  11. 28
      src/nailab/ui/strategywidget.py
  12. 8
      src/nailab/ui_gen/csvdatasourceconfigwidget.py
  13. 8
      src/nailab/ui_gen/equitychartwidget.py
  14. 17
      src/nailab/ui_gen/mainwindow.py
  15. 10
      src/nailab/ui_gen/newdatasourcedialog.py
  16. 10
      src/nailab/ui_gen/performancewidget.py
  17. 51
      src/nailab/ui_gen/settingswindow.py
  18. 62
      src/nailab/ui_gen/statisticwidget.py
  19. 29
      src/nailab/ui_gen/strategywidget.py
  20. 8
      src/nailab/ui_gen/tradeslistwidget.py
  21. 27
      ui/mainwindow.ui
  22. 5
      ui/newdatasourcedialog.ui
  23. 2
      ui/performancewidget.ui
  24. 105
      ui/settingswindow.ui
  25. 113
      ui/statisticwidget.ui
  26. 38
      ui/strategywidget.ui

20
build_ui.sh

@ -1,13 +1,15 @@ @@ -1,13 +1,15 @@
#!/bin/bash
/usr/bin/pyuic5 ui/csvdatasourceconfigwidget.ui > src/nailab/ui_gen/csvdatasourceconfigwidget.py
/usr/bin/pyuic5 ui/equitychartwidget.ui > src/nailab/ui_gen/equitychartwidget.py
/usr/bin/pyuic5 ui/mainwindow.ui > src/nailab/ui_gen/mainwindow.py
/usr/bin/pyuic5 ui/newdatasourcedialog.ui > src/nailab/ui_gen/newdatasourcedialog.py
/usr/bin/pyuic5 ui/strategywidget.ui > src/nailab/ui_gen/strategywidget.py
/usr/bin/pyuic5 ui/tradeslistwidget.ui > src/nailab/ui_gen/tradeslistwidget.py
/usr/bin/pyuic5 ui/performancewidget.ui > src/nailab/ui_gen/performancewidget.py
/usr/bin/pyrcc5 nailab.qrc -o src/nailab/nailab_rc.py
pyuic5 ui/csvdatasourceconfigwidget.ui > src/nailab/ui_gen/csvdatasourceconfigwidget.py
pyuic5 ui/equitychartwidget.ui > src/nailab/ui_gen/equitychartwidget.py
pyuic5 ui/mainwindow.ui > src/nailab/ui_gen/mainwindow.py
pyuic5 ui/newdatasourcedialog.ui > src/nailab/ui_gen/newdatasourcedialog.py
pyuic5 ui/strategywidget.ui > src/nailab/ui_gen/strategywidget.py
pyuic5 ui/tradeslistwidget.ui > src/nailab/ui_gen/tradeslistwidget.py
pyuic5 ui/performancewidget.ui > src/nailab/ui_gen/performancewidget.py
pyuic5 ui/settingswindow.ui > src/nailab/ui_gen/settingswindow.py
pyuic5 ui/statisticwidget.ui > src/nailab/ui_gen/statisticwidget.py
pyrcc5 nailab.qrc -o src/nailab/nailab_rc.py

3
src/nailab/data/datasourcemanager.py

@ -1,5 +1,6 @@ @@ -1,5 +1,6 @@
from data.csvfolderdatasource import CsvFolderDataSource
from data.yahoocsvfolderdatasource import YahooCsvFolderDataSource
class DataSourceManager:
@ -19,6 +20,8 @@ class DataSourceManager: @@ -19,6 +20,8 @@ class DataSourceManager:
for s in serialized:
if s[0] == "csv":
self.add_source(CsvFolderDataSource.deserialize(s[1]))
if s[0] == "yahoo_csv":
self.add_source(YahooCsvFolderDataSource.deserialize(s[1]))
def add_source(self, source):
self.sources.append(source)

44
src/nailab/data/yahoocsvfolderdatasource.py

@ -0,0 +1,44 @@ @@ -0,0 +1,44 @@
from data.datasource import DataSource
from naiback.data.feeds.yahoofeed import YahooCSVFeed
import glob
import os
class YahooCsvFolderDataSource(DataSource):
def __init__(self, name, path):
super().__init__(name)
self.type = "yahoo_csv"
self.path = path
self.feeds = []
self._discover_feeds()
@classmethod
def deserialize(self, data):
return YahooCsvFolderDataSource(data[0], data[1])
def serialize(self):
return (self.name, self.path)
def available_feeds(self):
return [f[1] for f in self.feeds]
def refresh(self):
self._discover_feeds()
def get_feed(self, feed_id):
for path, f_id in self.feeds:
if f_id == feed_id:
with open(path, 'r') as f:
return YahooCSVFeed(f)
raise NailabError('Unable to obtain feed: {}'.format(feed_id))
def _discover_feeds(self):
files = glob.glob(self.path + '/*.csv')
self.feeds = [(f, os.path.basename(f)) for f in files]

10
src/nailab/execution/executor.py

@ -3,6 +3,7 @@ import sys @@ -3,6 +3,7 @@ import sys
import importlib
from importlib.machinery import SourceFileLoader
import inspect
from PyQt5 import QtCore
from naiback.strategy import Strategy
@ -23,6 +24,9 @@ class Executor: @@ -23,6 +24,9 @@ class Executor:
for feed in feeds:
strategy.add_feed(feed)
(commission_percentage, commission_per_share) = self.load_commissions()
strategy.broker.set_commission(commission_percentage, commission_per_share)
if extents is None:
strategy.run()
else:
@ -34,3 +38,9 @@ class Executor: @@ -34,3 +38,9 @@ class Executor:
return (results, trades, equity)
def load_commissions(self):
s = QtCore.QSettings()
return (float(s.value("commission/percentage", 0)), float(s.value("commission/per_share", 0)))

27
src/nailab/execution/portfolioexecutor.py

@ -54,18 +54,28 @@ class PortfolioExecutor: @@ -54,18 +54,28 @@ class PortfolioExecutor:
all_trades = list(sorted(trades1 + trades2, key=lambda x: x['entry_time']))
result = []
current_trades = []
# TODO customize
size_per_position = 1000000
cash = 1000000
max_trades = 3
for trade in all_trades:
if len(current_trades) < max_trades:
size = math.floor(size_per_position / (trade['entry_price'] * max_trades))
cash -= size * trade['entry_price']
trade['size'] = size
if trade['is_long']:
trade['pnl'] = size * (trade['exit_price'] - trade['entry_price'])
else:
trade['pnl'] = -size * (trade['exit_price'] - trade['entry_price'])
current_trades.append(trade)
result.append(trade)
new_current_trades = []
for ct in current_trades:
if ct['exit_time'] < trade['entry_time']:
new_current_trades.append(ct)
else:
# possibly adjust the balance
pass
cash += ct['size'] * ct['exit_price']
current_trades = new_current_trades
return result
@ -90,6 +100,10 @@ class PortfolioExecutor: @@ -90,6 +100,10 @@ class PortfolioExecutor:
result['long']['number_of_trades'] = len(longs)
result['short']['number_of_trades'] = len(shorts)
result['all']['total_commission'] = 0 # TODO
result['long']['total_commission'] = 0
result['short']['total_commission'] = 0
result['all']['avg'] = render_ratio(result['all']['net_profit'], result['all']['number_of_trades'])
result['long']['avg'] = render_ratio(result['long']['net_profit'], result['long']['number_of_trades'])
result['short']['avg'] = render_ratio(result['short']['net_profit'], result['short']['number_of_trades'])
@ -126,22 +140,25 @@ class PortfolioExecutor: @@ -126,22 +140,25 @@ class PortfolioExecutor:
stddev = np.std(list(map(lambda x: x['pnl'], trades)))
sharpe = mean / stddev
tstat = sharpe * math.sqrt(len(trades))
result['all']['sharpe_ratio'] = sharpe
result['all']['z_score'] = sharpe
result['all']['t_stat'] = tstat
result['all']['kelly'] = 0
mean = np.mean(list(map(lambda x: x['pnl'], longs)))
stddev = np.std(list(map(lambda x: x['pnl'], longs)))
sharpe = mean / stddev
tstat = sharpe * math.sqrt(len(longs))
result['long']['sharpe_ratio'] = sharpe
result['long']['z_score'] = sharpe
result['long']['t_stat'] = tstat
result['long']['kelly'] = 0
mean = np.mean(list(map(lambda x: x['pnl'], shorts)))
stddev = np.std(list(map(lambda x: x['pnl'], shorts)))
sharpe = mean / stddev
tstat = sharpe * math.sqrt(len(shorts))
result['short']['sharpe_ratio'] = sharpe
result['short']['z_score'] = sharpe
result['short']['t_stat'] = tstat
result['short']['kelly'] = 0
return result

249
src/nailab/nailab_rc.py

@ -2,13 +2,110 @@ @@ -2,13 +2,110 @@
# Resource object code
#
# Created by: The Resource Compiler for PyQt5 (Qt v5.5.1)
# Created by: The Resource Compiler for PyQt5 (Qt v5.15.1)
#
# WARNING! All changes made in this file will be lost!
from PyQt5 import QtCore
qt_resource_data = b"\
\x00\x00\x03\x8f\
\x89\
\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
\x00\x00\x30\x00\x00\x00\x30\x08\x06\x00\x00\x00\x57\x02\xf9\x87\
\x00\x00\x00\x04\x73\x42\x49\x54\x08\x08\x08\x08\x7c\x08\x64\x88\
\x00\x00\x00\x09\x70\x48\x59\x73\x00\x00\x1b\xaf\x00\x00\x1b\xaf\
\x01\x5e\x1a\x91\x1c\x00\x00\x00\x19\x74\x45\x58\x74\x53\x6f\x66\
\x74\x77\x61\x72\x65\x00\x77\x77\x77\x2e\x69\x6e\x6b\x73\x63\x61\
\x70\x65\x2e\x6f\x72\x67\x9b\xee\x3c\x1a\x00\x00\x03\x0c\x49\x44\
\x41\x54\x68\x81\xed\x98\x3b\x6f\x13\x41\x14\x85\xcf\xdd\x75\x22\
\x2b\x7e\xc4\x8b\x82\xac\x74\x48\x3c\x44\x8f\x68\x20\x11\x54\x54\
\x54\x48\x20\x90\x22\x85\x9a\x74\x94\xbc\xc4\xa3\x83\x48\xf4\x54\
\x49\x41\x89\x8c\x22\x7e\x40\xc2\x8f\x48\x49\x81\x14\x51\x61\x93\
\x38\xb1\xe3\xd7\x5e\x0a\x6c\x65\xbc\x33\x76\x76\x66\xef\xda\x29\
\xf8\x24\x37\x33\x9e\xdd\x73\x76\xce\x1d\xdf\x35\x31\x33\x6c\xa9\
\x57\x82\x55\xaa\x7a\x1b\xda\x44\x96\x11\x5e\x08\xad\xaf\x07\xf0\
\x66\xf1\xe6\xfe\x63\x87\x85\xf0\x5c\x16\xa1\x45\x2f\x8c\x32\x02\
\xfb\x87\x01\xd0\xee\x51\x36\xff\xc4\x49\x07\x1c\x0c\x1c\x7c\x9b\
\xbf\x4c\x0d\xba\xa4\x4d\xf8\x00\x17\xad\x0d\x34\xbc\xb0\x7b\x7f\
\xf1\xda\x5e\xc3\x76\xe1\x00\x6b\x03\x7e\xd3\xff\x08\x83\x4e\x9e\
\x67\x80\xec\xae\x45\x44\x6b\xf9\xe5\xfa\xae\xad\x06\x15\x3b\x03\
\xdb\x94\xe1\x26\xee\x98\xa6\x38\xb0\xcd\x3e\x6f\x16\x6e\xd4\x36\
\x2c\x17\x69\x58\x19\x38\xa8\x96\x9e\xa3\x43\x33\x9a\x94\x3c\x03\
\xda\xe8\x38\x92\xe5\x5e\xc5\xca\x00\x1d\xd3\x9a\x71\xa2\x64\x95\
\xfd\xc4\xb9\x57\x89\x6d\xe0\xb0\x12\xdc\xa2\x26\x9d\xd7\x26\x66\
\xfa\x3b\x10\x13\x89\xdc\xab\xc4\x36\xc0\x1d\xbc\x37\x8e\x5b\x65\
\x5f\x26\xf7\x2a\xb1\x0c\xfc\xf9\x1a\x94\xa8\xe1\x5d\xd7\x26\xa8\
\x7f\xfa\xc4\x42\x2e\xf7\x2a\xb1\x0c\xf8\x5d\x7c\x40\x4f\x3f\x24\
\xb9\xc8\x80\x1f\xeb\x3e\xa2\xb9\x57\x89\x17\xa1\x63\xef\x91\x69\
\x38\xee\x2f\xaf\x74\xee\x55\x4e\x35\x50\xaf\x04\xab\xd4\x42\x4e\
\x9b\xc8\xf2\xbf\xcf\xa9\xc8\xe7\x5e\xe5\xf4\x1d\x48\xd4\xf7\xa4\
\x93\x7b\x95\xb1\x06\x12\xf6\x3d\xa9\xe5\x5e\x65\xac\x81\x24\x7d\
\x4f\x9a\xb9\x1f\xba\xcf\xc8\xf7\x81\x6d\xca\x1c\xfe\x0c\x1a\xa6\
\xd6\x21\xbc\xd8\xb3\x6c\x1d\x1c\x61\x7a\x53\x5c\xaa\xbd\x1e\xf7\
\x95\x91\x3b\x20\xd7\xf7\x38\x12\x43\x3c\x30\xc6\x80\x50\xdf\xe3\
\x46\x4c\xf1\xc0\x08\x03\x52\x7d\x8f\x13\x16\xe2\x81\x11\x06\x64\
\xfa\x1e\x07\x2c\xc5\x03\x06\x03\x32\x7d\x8f\x03\x0e\xe2\x01\x83\
\x01\xbf\xe7\xad\x27\xec\x7b\xec\x71\x14\x0f\x98\x22\xd4\xc4\x43\
\xe3\x3d\x9c\xfe\x71\x88\x41\x02\xf1\xc0\xb8\xdf\x01\x07\xaa\x9f\
\x16\x5f\xb6\xf6\xe6\xde\x46\xc7\xfd\xb9\x2e\xb2\x4b\xfb\xfa\x82\
\x84\xe2\x01\xd7\xff\x85\x46\x10\x1e\x66\x9e\x9a\xc6\x67\xae\x18\
\xba\x09\x01\xf1\x80\xe0\x0e\x1c\x6d\x95\xcb\xfc\xbb\xfb\x0b\xe1\
\x70\xfd\x70\xc0\xe0\x72\xe4\xf4\x12\x12\x0f\x08\xee\x40\xd8\xee\
\xac\x47\xc5\xc3\x07\x78\x21\x3d\xf1\x80\xa0\x01\x6a\xd2\xbd\xe8\
\x18\x2f\x84\xc3\x27\x97\xb0\x78\x40\xc8\xc0\xc1\x97\x73\x2b\x68\
\x63\x6e\x68\x70\x16\x60\xb5\xed\x48\x41\x3c\x20\x64\xc0\xeb\xe2\
\x59\x74\x8c\xcb\xe1\x49\xcb\x9d\x92\x78\x40\xc0\xc0\xd1\x56\xb9\
\x8c\x06\x5d\x55\xc7\x38\xc7\xe0\x5c\xff\xe9\xa7\x28\x1e\x10\x30\
\xa0\x15\x2f\xe1\xe4\xd4\x49\x59\x3c\x20\x60\x20\x5a\xbc\x5c\x62\
\x60\x16\x13\x11\x0f\x24\x34\xa0\x15\xef\xe0\xd8\x9c\x90\x78\x20\
\xa1\x81\x68\xf1\xf2\x42\x08\x78\x93\x13\x0f\x24\x30\xa0\x15\xef\
\x2c\xc0\xf3\x78\x37\x49\xf1\x40\x02\x03\x5a\xf1\x06\xfc\xb9\xb8\
\x5c\x7b\x25\xa2\xca\x02\x67\x03\x6a\xf1\x72\x81\x77\xf2\x77\xab\
\x2b\x32\x92\xec\x70\x32\xa0\x16\x2f\x17\x78\xa7\xf0\xa0\x7a\x5b\
\x54\x95\x05\x4e\x06\x06\xc5\x3b\x6d\xf1\x80\x43\x3b\x3d\x68\x9b\
\x39\xc7\xdf\xa7\x2d\x1e\x00\x32\xb6\x0b\xc2\x76\x67\x1d\x39\x9c\
\x09\xf1\x80\x43\x84\x88\xf8\xc7\x59\x11\x0f\x08\xbf\x13\x4f\x03\
\xd1\x77\xe2\x69\xf0\xdf\xc0\xb4\xf9\x0b\x47\x70\x6d\x4b\x01\x24\
\x0b\x02\x00\x00\x00\x00\x49\x45\x4e\x44\xae\x42\x60\x82\
\x00\x00\x02\x33\
\x89\
\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
\x00\x00\x30\x00\x00\x00\x30\x08\x06\x00\x00\x00\x57\x02\xf9\x87\
\x00\x00\x00\x04\x73\x42\x49\x54\x08\x08\x08\x08\x7c\x08\x64\x88\
\x00\x00\x00\x09\x70\x48\x59\x73\x00\x00\x1b\xaf\x00\x00\x1b\xaf\
\x01\x5e\x1a\x91\x1c\x00\x00\x00\x19\x74\x45\x58\x74\x53\x6f\x66\
\x74\x77\x61\x72\x65\x00\x77\x77\x77\x2e\x69\x6e\x6b\x73\x63\x61\
\x70\x65\x2e\x6f\x72\x67\x9b\xee\x3c\x1a\x00\x00\x01\xb0\x49\x44\
\x41\x54\x68\x81\xed\x9a\x31\x6a\x02\x41\x14\x86\xff\x59\x05\x25\
\x8d\x21\x10\xc1\xca\x23\xd8\x06\x1b\x21\x5d\xae\x13\x1b\xab\x14\
\xc1\xc2\x2a\xe7\xf0\x14\x42\x9a\x25\x6d\x4e\x10\x2c\x12\x83\x1b\
\x16\x5d\x31\xba\xee\xcc\xbc\x14\x21\x90\x80\x6f\xd0\xe8\xfa\x58\
\x98\xaf\xdc\x19\xd8\xef\x73\xc6\xb1\x18\x15\x11\xa1\xc8\x04\xd2\
\x02\x87\x52\x76\x0d\x8e\xc2\xb0\x09\x1b\x0c\x08\xd4\x51\x50\x8d\
\x53\x49\x01\x00\x81\x26\x0a\xea\x11\x81\xed\x5d\xb7\xdb\x63\x6e\
\x9e\xe2\xb6\xd0\x28\x0c\x9b\xa0\xe0\x19\x84\x5a\x6e\x96\xbb\xa0\
\x30\x87\xb2\x2d\x2e\x82\xdf\x42\x36\x18\x88\xcb\x03\x00\xa1\x06\
\x1b\x0c\xb8\x61\x36\x80\x40\x9d\x7c\x8c\xf6\xc7\xe5\xc2\x06\x9c\
\x7a\xcf\xbb\x70\xb9\x14\xfe\x14\xf2\x01\xd2\xf8\x00\x69\x7c\x80\
\x34\x3e\x40\x1a\x1f\x20\x8d\x0f\x90\xc6\x07\x48\xe3\x03\xa4\xf1\
\x01\xd2\xf8\x00\x69\x7c\x80\x34\x3e\x40\x1a\x1f\x20\x0d\x1b\xa0\
\x8d\x39\xa5\x87\x13\x97\x0b\x1b\xf0\x99\xae\x73\x91\xf9\x0f\x2e\
\x17\x36\x20\x9a\xc5\xb0\xd6\xe6\x22\xb4\x0f\xd6\x5a\x44\xb3\x98\
\x1d\x67\xaf\x98\x32\xad\xf1\xf2\xfe\x8a\xcb\xf3\x0b\x9c\x55\xaa\
\x28\x97\x4a\xb9\x08\x72\x6c\xb2\x0d\xe6\x49\x82\x24\x5d\x21\xd3\
\x9a\x9d\xe7\xbc\x23\xcb\xb4\xc6\xdb\xc7\xf4\xe8\x72\x00\x30\x9d\
\x4c\x76\x9a\x57\x6f\xb8\xaf\x29\x0a\x7f\x0a\xb1\x2b\x60\xad\x45\
\x10\xe4\xdf\x77\x7b\x75\xbf\xf5\xf9\xc3\xd3\xdd\x1f\x17\x0e\xd6\
\x70\x93\xa6\x07\x68\x1d\x17\x97\x0b\xbb\x02\xcb\xc5\x62\x5a\xa9\
\x56\xeb\x4a\xa9\x5c\xa4\x7e\xf8\xfd\x49\x6f\x83\x88\xb0\x5c\x2c\
\xd8\x2f\x22\xbb\x02\xc6\xe8\x51\x1c\x45\x58\xaf\x56\xa2\xc7\x69\
\x1c\x45\x30\x46\x8f\xb8\x71\x76\x05\x34\xd0\x53\xc6\xdc\x24\xb3\
\x99\xe8\x5d\xb1\x35\x66\xae\x81\x1e\x37\xce\xae\x40\xbf\xdb\x1d\
\x67\xa0\x16\x40\x43\x05\xec\x76\xe6\x1d\x91\xef\x77\xd2\x30\x03\
\xb5\xfa\xdd\xee\xfe\x7f\x35\x28\x0a\x85\xff\x1d\xf8\x02\xd1\xfa\
\xa2\xe7\x75\x3b\xf6\xd5\x00\x00\x00\x00\x49\x45\x4e\x44\xae\x42\
\x60\x82\
\x00\x00\x02\x0e\
\x89\
\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
@ -87,103 +184,6 @@ qt_resource_data = b"\ @@ -87,103 +184,6 @@ qt_resource_data = b"\
\x41\xe9\x31\x00\xcb\x38\xfb\x94\x19\x77\x07\x00\x96\xa1\xf4\x58\
\x31\x9f\x2d\x91\xfb\xb7\x8a\x65\x3f\x00\xdf\xf9\xa7\x43\x02\xf4\
\x78\xd9\x00\x00\x00\x00\x49\x45\x4e\x44\xae\x42\x60\x82\
\x00\x00\x02\x33\
\x89\
\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
\x00\x00\x30\x00\x00\x00\x30\x08\x06\x00\x00\x00\x57\x02\xf9\x87\
\x00\x00\x00\x04\x73\x42\x49\x54\x08\x08\x08\x08\x7c\x08\x64\x88\
\x00\x00\x00\x09\x70\x48\x59\x73\x00\x00\x1b\xaf\x00\x00\x1b\xaf\
\x01\x5e\x1a\x91\x1c\x00\x00\x00\x19\x74\x45\x58\x74\x53\x6f\x66\
\x74\x77\x61\x72\x65\x00\x77\x77\x77\x2e\x69\x6e\x6b\x73\x63\x61\
\x70\x65\x2e\x6f\x72\x67\x9b\xee\x3c\x1a\x00\x00\x01\xb0\x49\x44\
\x41\x54\x68\x81\xed\x9a\x31\x6a\x02\x41\x14\x86\xff\x59\x05\x25\
\x8d\x21\x10\xc1\xca\x23\xd8\x06\x1b\x21\x5d\xae\x13\x1b\xab\x14\
\xc1\xc2\x2a\xe7\xf0\x14\x42\x9a\x25\x6d\x4e\x10\x2c\x12\x83\x1b\
\x16\x5d\x31\xba\xee\xcc\xbc\x14\x21\x90\x80\x6f\xd0\xe8\xfa\x58\
\x98\xaf\xdc\x19\xd8\xef\x73\xc6\xb1\x18\x15\x11\xa1\xc8\x04\xd2\
\x02\x87\x52\x76\x0d\x8e\xc2\xb0\x09\x1b\x0c\x08\xd4\x51\x50\x8d\
\x53\x49\x01\x00\x81\x26\x0a\xea\x11\x81\xed\x5d\xb7\xdb\x63\x6e\
\x9e\xe2\xb6\xd0\x28\x0c\x9b\xa0\xe0\x19\x84\x5a\x6e\x96\xbb\xa0\
\x30\x87\xb2\x2d\x2e\x82\xdf\x42\x36\x18\x88\xcb\x03\x00\xa1\x06\
\x1b\x0c\xb8\x61\x36\x80\x40\x9d\x7c\x8c\xf6\xc7\xe5\xc2\x06\x9c\
\x7a\xcf\xbb\x70\xb9\x14\xfe\x14\xf2\x01\xd2\xf8\x00\x69\x7c\x80\
\x34\x3e\x40\x1a\x1f\x20\x8d\x0f\x90\xc6\x07\x48\xe3\x03\xa4\xf1\
\x01\xd2\xf8\x00\x69\x7c\x80\x34\x3e\x40\x1a\x1f\x20\x0d\x1b\xa0\
\x8d\x39\xa5\x87\x13\x97\x0b\x1b\xf0\x99\xae\x73\x91\xf9\x0f\x2e\
\x17\x36\x20\x9a\xc5\xb0\xd6\xe6\x22\xb4\x0f\xd6\x5a\x44\xb3\x98\
\x1d\x67\xaf\x98\x32\xad\xf1\xf2\xfe\x8a\xcb\xf3\x0b\x9c\x55\xaa\
\x28\x97\x4a\xb9\x08\x72\x6c\xb2\x0d\xe6\x49\x82\x24\x5d\x21\xd3\
\x9a\x9d\xe7\xbc\x23\xcb\xb4\xc6\xdb\xc7\xf4\xe8\x72\x00\x30\x9d\
\x4c\x76\x9a\x57\x6f\xb8\xaf\x29\x0a\x7f\x0a\xb1\x2b\x60\xad\x45\
\x10\xe4\xdf\x77\x7b\x75\xbf\xf5\xf9\xc3\xd3\xdd\x1f\x17\x0e\xd6\
\x70\x93\xa6\x07\x68\x1d\x17\x97\x0b\xbb\x02\xcb\xc5\x62\x5a\xa9\
\x56\xeb\x4a\xa9\x5c\xa4\x7e\xf8\xfd\x49\x6f\x83\x88\xb0\x5c\x2c\
\xd8\x2f\x22\xbb\x02\xc6\xe8\x51\x1c\x45\x58\xaf\x56\xa2\xc7\x69\
\x1c\x45\x30\x46\x8f\xb8\x71\x76\x05\x34\xd0\x53\xc6\xdc\x24\xb3\
\x99\xe8\x5d\xb1\x35\x66\xae\x81\x1e\x37\xce\xae\x40\xbf\xdb\x1d\
\x67\xa0\x16\x40\x43\x05\xec\x76\xe6\x1d\x91\xef\x77\xd2\x30\x03\
\xb5\xfa\xdd\xee\xfe\x7f\x35\x28\x0a\x85\xff\x1d\xf8\x02\xd1\xfa\
\xa2\xe7\x75\x3b\xf6\xd5\x00\x00\x00\x00\x49\x45\x4e\x44\xae\x42\
\x60\x82\
\x00\x00\x03\x8f\
\x89\
\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
\x00\x00\x30\x00\x00\x00\x30\x08\x06\x00\x00\x00\x57\x02\xf9\x87\
\x00\x00\x00\x04\x73\x42\x49\x54\x08\x08\x08\x08\x7c\x08\x64\x88\
\x00\x00\x00\x09\x70\x48\x59\x73\x00\x00\x1b\xaf\x00\x00\x1b\xaf\
\x01\x5e\x1a\x91\x1c\x00\x00\x00\x19\x74\x45\x58\x74\x53\x6f\x66\
\x74\x77\x61\x72\x65\x00\x77\x77\x77\x2e\x69\x6e\x6b\x73\x63\x61\
\x70\x65\x2e\x6f\x72\x67\x9b\xee\x3c\x1a\x00\x00\x03\x0c\x49\x44\
\x41\x54\x68\x81\xed\x98\x3b\x6f\x13\x41\x14\x85\xcf\xdd\x75\x22\
\x2b\x7e\xc4\x8b\x82\xac\x74\x48\x3c\x44\x8f\x68\x20\x11\x54\x54\
\x54\x48\x20\x90\x22\x85\x9a\x74\x94\xbc\xc4\xa3\x83\x48\xf4\x54\
\x49\x41\x89\x8c\x22\x7e\x40\xc2\x8f\x48\x49\x81\x14\x51\x61\x93\
\x38\xb1\xe3\xd7\x5e\x0a\x6c\x65\xbc\x33\x76\x76\x66\xef\xda\x29\
\xf8\x24\x37\x33\x9e\xdd\x73\x76\xce\x1d\xdf\x35\x31\x33\x6c\xa9\
\x57\x82\x55\xaa\x7a\x1b\xda\x44\x96\x11\x5e\x08\xad\xaf\x07\xf0\
\x66\xf1\xe6\xfe\x63\x87\x85\xf0\x5c\x16\xa1\x45\x2f\x8c\x32\x02\
\xfb\x87\x01\xd0\xee\x51\x36\xff\xc4\x49\x07\x1c\x0c\x1c\x7c\x9b\
\xbf\x4c\x0d\xba\xa4\x4d\xf8\x00\x17\xad\x0d\x34\xbc\xb0\x7b\x7f\
\xf1\xda\x5e\xc3\x76\xe1\x00\x6b\x03\x7e\xd3\xff\x08\x83\x4e\x9e\
\x67\x80\xec\xae\x45\x44\x6b\xf9\xe5\xfa\xae\xad\x06\x15\x3b\x03\
\xdb\x94\xe1\x26\xee\x98\xa6\x38\xb0\xcd\x3e\x6f\x16\x6e\xd4\x36\
\x2c\x17\x69\x58\x19\x38\xa8\x96\x9e\xa3\x43\x33\x9a\x94\x3c\x03\
\xda\xe8\x38\x92\xe5\x5e\xc5\xca\x00\x1d\xd3\x9a\x71\xa2\x64\x95\
\xfd\xc4\xb9\x57\x89\x6d\xe0\xb0\x12\xdc\xa2\x26\x9d\xd7\x26\x66\
\xfa\x3b\x10\x13\x89\xdc\xab\xc4\x36\xc0\x1d\xbc\x37\x8e\x5b\x65\
\x5f\x26\xf7\x2a\xb1\x0c\xfc\xf9\x1a\x94\xa8\xe1\x5d\xd7\x26\xa8\
\x7f\xfa\xc4\x42\x2e\xf7\x2a\xb1\x0c\xf8\x5d\x7c\x40\x4f\x3f\x24\
\xb9\xc8\x80\x1f\xeb\x3e\xa2\xb9\x57\x89\x17\xa1\x63\xef\x91\x69\
\x38\xee\x2f\xaf\x74\xee\x55\x4e\x35\x50\xaf\x04\xab\xd4\x42\x4e\
\x9b\xc8\xf2\xbf\xcf\xa9\xc8\xe7\x5e\xe5\xf4\x1d\x48\xd4\xf7\xa4\
\x93\x7b\x95\xb1\x06\x12\xf6\x3d\xa9\xe5\x5e\x65\xac\x81\x24\x7d\
\x4f\x9a\xb9\x1f\xba\xcf\xc8\xf7\x81\x6d\xca\x1c\xfe\x0c\x1a\xa6\
\xd6\x21\xbc\xd8\xb3\x6c\x1d\x1c\x61\x7a\x53\x5c\xaa\xbd\x1e\xf7\
\x95\x91\x3b\x20\xd7\xf7\x38\x12\x43\x3c\x30\xc6\x80\x50\xdf\xe3\
\x46\x4c\xf1\xc0\x08\x03\x52\x7d\x8f\x13\x16\xe2\x81\x11\x06\x64\
\xfa\x1e\x07\x2c\xc5\x03\x06\x03\x32\x7d\x8f\x03\x0e\xe2\x01\x83\
\x01\xbf\xe7\xad\x27\xec\x7b\xec\x71\x14\x0f\x98\x22\xd4\xc4\x43\
\xe3\x3d\x9c\xfe\x71\x88\x41\x02\xf1\xc0\xb8\xdf\x01\x07\xaa\x9f\
\x16\x5f\xb6\xf6\xe6\xde\x46\xc7\xfd\xb9\x2e\xb2\x4b\xfb\xfa\x82\
\x84\xe2\x01\xd7\xff\x85\x46\x10\x1e\x66\x9e\x9a\xc6\x67\xae\x18\
\xba\x09\x01\xf1\x80\xe0\x0e\x1c\x6d\x95\xcb\xfc\xbb\xfb\x0b\xe1\
\x70\xfd\x70\xc0\xe0\x72\xe4\xf4\x12\x12\x0f\x08\xee\x40\xd8\xee\
\xac\x47\xc5\xc3\x07\x78\x21\x3d\xf1\x80\xa0\x01\x6a\xd2\xbd\xe8\
\x18\x2f\x84\xc3\x27\x97\xb0\x78\x40\xc8\xc0\xc1\x97\x73\x2b\x68\
\x63\x6e\x68\x70\x16\x60\xb5\xed\x48\x41\x3c\x20\x64\xc0\xeb\xe2\
\x59\x74\x8c\xcb\xe1\x49\xcb\x9d\x92\x78\x40\xc0\xc0\xd1\x56\xb9\
\x8c\x06\x5d\x55\xc7\x38\xc7\xe0\x5c\xff\xe9\xa7\x28\x1e\x10\x30\
\xa0\x15\x2f\xe1\xe4\xd4\x49\x59\x3c\x20\x60\x20\x5a\xbc\x5c\x62\
\x60\x16\x13\x11\x0f\x24\x34\xa0\x15\xef\xe0\xd8\x9c\x90\x78\x20\
\xa1\x81\x68\xf1\xf2\x42\x08\x78\x93\x13\x0f\x24\x30\xa0\x15\xef\
\x2c\xc0\xf3\x78\x37\x49\xf1\x40\x02\x03\x5a\xf1\x06\xfc\xb9\xb8\
\x5c\x7b\x25\xa2\xca\x02\x67\x03\x6a\xf1\x72\x81\x77\xf2\x77\xab\
\x2b\x32\x92\xec\x70\x32\xa0\x16\x2f\x17\x78\xa7\xf0\xa0\x7a\x5b\
\x54\x95\x05\x4e\x06\x06\xc5\x3b\x6d\xf1\x80\x43\x3b\x3d\x68\x9b\
\x39\xc7\xdf\xa7\x2d\x1e\x00\x32\xb6\x0b\xc2\x76\x67\x1d\x39\x9c\
\x09\xf1\x80\x43\x84\x88\xf8\xc7\x59\x11\x0f\x08\xbf\x13\x4f\x03\
\xd1\x77\xe2\x69\xf0\xdf\xc0\xb4\xf9\x0b\x47\x70\x6d\x4b\x01\x24\
\x0b\x02\x00\x00\x00\x00\x49\x45\x4e\x44\xae\x42\x60\x82\
"
qt_resource_name = b"\
@ -195,6 +195,14 @@ qt_resource_name = b"\ @@ -195,6 +195,14 @@ qt_resource_name = b"\
\x00\x6f\xa6\x53\
\x00\x69\
\x00\x63\x00\x6f\x00\x6e\x00\x73\
\x00\x0b\
\x0c\x81\x80\x07\
\x00\x65\
\x00\x78\x00\x65\x00\x63\x00\x75\x00\x74\x00\x65\x00\x2e\x00\x70\x00\x6e\x00\x67\
\x00\x08\
\x08\xc8\x58\x67\
\x00\x73\
\x00\x61\x00\x76\x00\x65\x00\x2e\x00\x70\x00\x6e\x00\x67\
\x00\x07\
\x04\xca\x57\xa7\
\x00\x6e\
@ -203,30 +211,47 @@ qt_resource_name = b"\ @@ -203,30 +211,47 @@ qt_resource_name = b"\
\x06\xc1\x59\x87\
\x00\x6f\
\x00\x70\x00\x65\x00\x6e\x00\x2e\x00\x70\x00\x6e\x00\x67\
\x00\x08\
\x08\xc8\x58\x67\
\x00\x73\
\x00\x61\x00\x76\x00\x65\x00\x2e\x00\x70\x00\x6e\x00\x67\
\x00\x0b\
\x0c\x81\x80\x07\
\x00\x65\
\x00\x78\x00\x65\x00\x63\x00\x75\x00\x74\x00\x65\x00\x2e\x00\x70\x00\x6e\x00\x67\
"
qt_resource_struct = b"\
qt_resource_struct_v1 = b"\
\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x01\
\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x02\
\x00\x00\x00\x0e\x00\x02\x00\x00\x00\x04\x00\x00\x00\x03\
\x00\x00\x00\x50\x00\x00\x00\x00\x00\x01\x00\x00\x05\xca\
\x00\x00\x00\x64\x00\x00\x00\x00\x00\x01\x00\x00\x07\xdc\
\x00\x00\x00\x3a\x00\x00\x00\x00\x00\x01\x00\x00\x03\x93\
\x00\x00\x00\x1e\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\
\x00\x00\x00\x32\x00\x00\x00\x00\x00\x01\x00\x00\x02\x12\
\x00\x00\x00\x48\x00\x00\x00\x00\x00\x01\x00\x00\x04\xa5\
\x00\x00\x00\x5e\x00\x00\x00\x00\x00\x01\x00\x00\x06\xdc\
"
qt_resource_struct_v2 = b"\
\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x01\
\x00\x00\x00\x00\x00\x00\x00\x00\
\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x02\
\x00\x00\x00\x00\x00\x00\x00\x00\
\x00\x00\x00\x0e\x00\x02\x00\x00\x00\x04\x00\x00\x00\x03\
\x00\x00\x00\x00\x00\x00\x00\x00\
\x00\x00\x00\x50\x00\x00\x00\x00\x00\x01\x00\x00\x05\xca\
\x00\x00\x01\x47\xc9\x98\x5f\x00\
\x00\x00\x00\x64\x00\x00\x00\x00\x00\x01\x00\x00\x07\xdc\
\x00\x00\x01\x47\xc9\x98\x5f\x00\
\x00\x00\x00\x3a\x00\x00\x00\x00\x00\x01\x00\x00\x03\x93\
\x00\x00\x01\x47\xc9\x98\x5f\x00\
\x00\x00\x00\x1e\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\
\x00\x00\x01\x47\xc9\x98\x5f\x00\
"
qt_version = [int(v) for v in QtCore.qVersion().split('.')]
if qt_version < [5, 8, 0]:
rcc_version = 1
qt_resource_struct = qt_resource_struct_v1
else:
rcc_version = 2
qt_resource_struct = qt_resource_struct_v2
def qInitResources():
QtCore.qRegisterResourceData(0x01, qt_resource_struct, qt_resource_name, qt_resource_data)
QtCore.qRegisterResourceData(rcc_version, qt_resource_struct, qt_resource_name, qt_resource_data)
def qCleanupResources():
QtCore.qUnregisterResourceData(0x01, qt_resource_struct, qt_resource_name, qt_resource_data)
QtCore.qUnregisterResourceData(rcc_version, qt_resource_struct, qt_resource_name, qt_resource_data)
qInitResources()

7
src/nailab/ui/mainwindow.py

@ -16,6 +16,7 @@ from PyQt5.Qsci import * @@ -16,6 +16,7 @@ from PyQt5.Qsci import *
from ui_gen.mainwindow import Ui_MainWindow
from ui.strategywidget import StrategyWidget
from ui.performancewidget import PerformanceWidget
from ui.settingswindow import SettingsWindow
from naiback.strategy import Strategy
from templates.new_strategy import new_strategy_template
@ -117,6 +118,12 @@ class MainWindow(QtWidgets.QMainWindow): @@ -117,6 +118,12 @@ class MainWindow(QtWidgets.QMainWindow):
self.ui.tabs.widget(tab_index).save_state()
self.ui.tabs.removeTab(tab_index)
def showSettingsDialog(self):
dlg = SettingsWindow(self)
dlg.exec()
if dlg.result() == QtWidgets.QDialog.Accepted:
dlg.saveSettings()
def performanceAnalysis(self):
self.ui.tabs.addTab(PerformanceWidget(), self.tr("Performance analysis"))

6
src/nailab/ui/newdatasourcedialog.py

@ -6,6 +6,7 @@ from ui_gen.newdatasourcedialog import Ui_NewDataSourceDialog @@ -6,6 +6,7 @@ from ui_gen.newdatasourcedialog import Ui_NewDataSourceDialog
from ui.csvdatasourceconfigwidget import CSVDataSourceConfigWidget
from data.csvfolderdatasource import CsvFolderDataSource
from data.yahoocsvfolderdatasource import YahooCsvFolderDataSource
class NewDataSourceDialog(QtWidgets.QDialog):
@ -19,6 +20,7 @@ class NewDataSourceDialog(QtWidgets.QDialog): @@ -19,6 +20,7 @@ class NewDataSourceDialog(QtWidgets.QDialog):
self.ui.widgets.setCurrentIndex(index)
def get_data_source(self):
if self.ui.cb_sourceType.currentText() == "CSV":
return CsvFolderDataSource(self.ui.e_sourceName.text(), self.ui.widgets.currentWidget().ui.e_path.text())
else:
return YahooCsvFolderDataSource(self.ui.e_sourceName.text(), self.ui.widgets.currentWidget().ui.e_path.text())

26
src/nailab/ui/settingswindow.py

@ -0,0 +1,26 @@ @@ -0,0 +1,26 @@
from ui_gen.settingswindow import Ui_SettingsWindow
from PyQt5 import QtCore, QtGui, QtWidgets
class SettingsWindow(QtWidgets.QDialog):
def __init__(self, parent=None):
super().__init__(parent)
self.ui = Ui_SettingsWindow()
self.ui.setupUi(self)
self.loadSettings()
def loadSettings(self):
s = QtCore.QSettings()
self.ui.sb_commissionPercentage.setValue(float(s.value("commission/percentage", 0)));
self.ui.sb_commissionPerShare.setValue(float(s.value("commission/per_share", 0)))
def saveSettings(self):
s = QtCore.QSettings()
s.setValue("commission/percentage", float(self.ui.sb_commissionPercentage.value()))
s.setValue("commission/per_share", float(self.ui.sb_commissionPerShare.value()))

117
src/nailab/ui/statisticwidget.py

@ -0,0 +1,117 @@ @@ -0,0 +1,117 @@
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.Qsci import *
from ui_gen.statisticwidget import Ui_StatisticWidget
import math
def calc_ratio(a, b):
if b != 0:
return a / b
else:
return 0
class StatisticWidget(QtWidgets.QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.ui = Ui_StatisticWidget()
self.ui.setupUi(self)
self.trades = []
def set_trades(self, trades):
self.trades = trades
self.update_statistic()
def update_statistic(self):
self.update_by_ticker()
self.update_seasonality()
def update_by_ticker(self):
self.ui.tw_byTicker.clear()
by_ticker = {}
for trade in self.trades:
try:
by_ticker[trade["security"]].append(trade)
except KeyError:
by_ticker[trade["security"]] = [trade]
for ticker, trades in by_ticker.items():
item = QtWidgets.QTreeWidgetItem(self.ui.tw_byTicker)
stats = self.calc_stats(trades)
item.setText(0, ticker)
item.setText(1, "{:.4f}".format(stats["net_profit"]))
item.setText(2, "{}".format(stats["total_trades"]))
item.setText(3, "{:.2f}%".format(stats["avg_percentage"]))
def calc_stats(self, trades):
net_profit = 0
sum_percentage = 0
for trade in trades:
sum_percentage += trade["profit_percentage"]
net_profit += trade["pnl"]
return { "net_profit" : net_profit,
"total_trades" : len(trades),
"avg_percentage" : calc_ratio(sum_percentage, len(trades)) }
def update_seasonality(self ):
self.ui.tw_seasonality.clear()
by_weekday = {}
by_monthday = {}
by_month = {}
for trade in self.trades:
try:
by_weekday[trade["entry_time"].date().isoweekday()].append(trade)
except KeyError:
by_weekday[trade["entry_time"].date().isoweekday()] = [trade]
try:
by_monthday[trade["entry_time"].date().day].append(trade)
except KeyError:
by_monthday[trade["entry_time"].date().day] = [trade]
try:
by_month[trade["entry_time"].date().month].append(trade)
except KeyError:
by_month[trade["entry_time"].date().month] = [trade]
item_by_weekday = QtWidgets.QTreeWidgetItem(self.ui.tw_seasonality)
item_by_weekday.setText(0, "By weekday")
for weekday, trades in sorted(by_weekday.items()):
item = QtWidgets.QTreeWidgetItem(item_by_weekday)
stats = self.calc_stats(trades)
item.setText(0, "{}".format(weekday))
item.setText(1, "{:.4f}".format(stats["net_profit"]))
item.setText(2, "{}".format(stats["total_trades"]))
item.setText(3, "{:.2f}%".format(stats["avg_percentage"]))
item_by_monthday = QtWidgets.QTreeWidgetItem(self.ui.tw_seasonality)
item_by_monthday.setText(0, "By day-of-month")
for monthday, trades in sorted(by_monthday.items()):
item = QtWidgets.QTreeWidgetItem(item_by_monthday)
stats = self.calc_stats(trades)
item.setText(0, "{:02d}".format(monthday))
item.setText(1, "{:.4f}".format(stats["net_profit"]))
item.setText(2, "{}".format(stats["total_trades"]))
item.setText(3, "{:.2f}%".format(stats["avg_percentage"]))
item_by_month = QtWidgets.QTreeWidgetItem(self.ui.tw_seasonality)
item_by_month.setText(0, "By month")
for month, trades in sorted(by_month.items()):
item = QtWidgets.QTreeWidgetItem(item_by_month)
stats = self.calc_stats(trades)
item.setText(0, "{:02d}".format(month))
item.setText(1, "{:.4f}".format(stats["net_profit"]))
item.setText(2, "{}".format(stats["total_trades"]))
item.setText(3, "{:.2f}%".format(stats["avg_percentage"]))

28
src/nailab/ui/strategywidget.py

@ -11,6 +11,7 @@ from ui_gen.strategywidget import Ui_StrategyWidget @@ -11,6 +11,7 @@ from ui_gen.strategywidget import Ui_StrategyWidget
from ui.newdatasourcedialog import NewDataSourceDialog
from ui.equitychartwidget import EquityChartWidget
from ui.tradeslistwidget import TradesListWidget
from ui.statisticwidget import StatisticWidget
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler
@ -76,6 +77,7 @@ class StrategyWidget(QtWidgets.QWidget): @@ -76,6 +77,7 @@ class StrategyWidget(QtWidgets.QWidget):
self.result_widget = None
self.equity_widget = None
self.trades_widget = None
self.statistic_widget = None
self.watchdog_handler = FileModifiedHandler(self.file_modified)
self.watchdog = None
@ -223,8 +225,12 @@ class StrategyWidget(QtWidgets.QWidget): @@ -223,8 +225,12 @@ class StrategyWidget(QtWidgets.QWidget):
self.trades_widget = TradesListWidget(self)
self.ui.tabs.addTab(self.trades_widget, "Trades")
self.trades_widget.set_trades(self.result[1])
if self.statistic_widget is None:
self.statistic_widget = StatisticWidget(self)
self.ui.tabs.addTab(self.statistic_widget, "Statistic")
self.trades_widget.set_trades(self.result[1])
self.statistic_widget.set_trades(self.result[1])
def update_result(self):
if self.result_widget is None:
@ -265,6 +271,12 @@ class StrategyWidget(QtWidgets.QWidget): @@ -265,6 +271,12 @@ class StrategyWidget(QtWidgets.QWidget):
net_profit.setText(2, "{:.3f}".format(self.result[0]['short']['net_profit']))
net_profit.setText(3, "{:.3f}".format(self.result[0]['all']['net_profit']))
total_commission = QtWidgets.QTreeWidgetItem(self.result_widget)
total_commission.setText(0, "Total commission")
total_commission.setText(1, "{:.3f}".format(self.result[0]['long']['total_commission']))
total_commission.setText(2, "{:.3f}".format(self.result[0]['short']['total_commission']))
total_commission.setText(3, "{:.3f}".format(self.result[0]['all']['total_commission']))
total_won = QtWidgets.QTreeWidgetItem(self.result_widget)
total_won.setText(0, "Total won")
total_won.setText(1, "{:.3f}".format(self.result[0]['long']['total_won']))
@ -302,10 +314,10 @@ class StrategyWidget(QtWidgets.QWidget): @@ -302,10 +314,10 @@ class StrategyWidget(QtWidgets.QWidget):
profit_factor.setText(3, "{:.3f}".format(self.result[0]['all']['profit_factor']))
sharpe_ratio = QtWidgets.QTreeWidgetItem(self.result_widget)
sharpe_ratio.setText(0, "Sharpe ratio")
sharpe_ratio.setText(1, "{:.3f}".format(self.result[0]['long']['sharpe_ratio']))
sharpe_ratio.setText(2, "{:.3f}".format(self.result[0]['short']['sharpe_ratio']))
sharpe_ratio.setText(3, "{:.3f}".format(self.result[0]['all']['sharpe_ratio']))
sharpe_ratio.setText(0, "Z-score")
sharpe_ratio.setText(1, "{:.3f}".format(self.result[0]['long']['z_score']))
sharpe_ratio.setText(2, "{:.3f}".format(self.result[0]['short']['z_score']))
sharpe_ratio.setText(3, "{:.3f}".format(self.result[0]['all']['z_score']))
t_stat = QtWidgets.QTreeWidgetItem(self.result_widget)
t_stat.setText(0, "t-statistics")
@ -313,6 +325,12 @@ class StrategyWidget(QtWidgets.QWidget): @@ -313,6 +325,12 @@ class StrategyWidget(QtWidgets.QWidget):
t_stat.setText(2, "{:.3f}".format(self.result[0]['short']['t_stat']))
t_stat.setText(3, "{:.3f}".format(self.result[0]['all']['t_stat']))
kelly = QtWidgets.QTreeWidgetItem(self.result_widget)
kelly.setText(0, "Kelly ratio")
kelly.setText(1, "{:.1f}%".format(100. * self.result[0]['long']['kelly']))
kelly.setText(2, "{:.1f}%".format(100. * self.result[0]['short']['kelly']))
kelly.setText(3, "{:.1f}%".format(100. * self.result[0]['all']['kelly']))
self.result_widget.resizeColumnToContents(0)
def setError(self, errmsg):

8
src/nailab/ui_gen/csvdatasourceconfigwidget.py

@ -2,12 +2,15 @@ @@ -2,12 +2,15 @@
# Form implementation generated from reading ui file 'ui/csvdatasourceconfigwidget.ui'
#
# Created by: PyQt5 UI code generator 5.5.1
# Created by: PyQt5 UI code generator 5.15.1
#
# WARNING! All changes made in this file will be lost!
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing.
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_CSVDataSourceConfigWidget(object):
def setupUi(self, CSVDataSourceConfigWidget):
CSVDataSourceConfigWidget.setObjectName("CSVDataSourceConfigWidget")
@ -45,4 +48,3 @@ class Ui_CSVDataSourceConfigWidget(object): @@ -45,4 +48,3 @@ class Ui_CSVDataSourceConfigWidget(object):
CSVDataSourceConfigWidget.setWindowTitle(_translate("CSVDataSourceConfigWidget", "Form"))
self.label.setText(_translate("CSVDataSourceConfigWidget", "CSV folder path"))
self.b_browse.setText(_translate("CSVDataSourceConfigWidget", "..."))

8
src/nailab/ui_gen/equitychartwidget.py

@ -2,12 +2,15 @@ @@ -2,12 +2,15 @@
# Form implementation generated from reading ui file 'ui/equitychartwidget.ui'
#
# Created by: PyQt5 UI code generator 5.5.1
# Created by: PyQt5 UI code generator 5.15.1
#
# WARNING! All changes made in this file will be lost!
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing.
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_EquityChartWidget(object):
def setupUi(self, EquityChartWidget):
EquityChartWidget.setObjectName("EquityChartWidget")
@ -24,5 +27,4 @@ class Ui_EquityChartWidget(object): @@ -24,5 +27,4 @@ class Ui_EquityChartWidget(object):
def retranslateUi(self, EquityChartWidget):
_translate = QtCore.QCoreApplication.translate
EquityChartWidget.setWindowTitle(_translate("EquityChartWidget", "Form"))
from ui.equitychartcanvas import EquityChartCanvas

17
src/nailab/ui_gen/mainwindow.py

@ -2,16 +2,19 @@ @@ -2,16 +2,19 @@
# Form implementation generated from reading ui file 'ui/mainwindow.ui'
#
# Created by: PyQt5 UI code generator 5.5.1
# Created by: PyQt5 UI code generator 5.15.1
#
# WARNING! All changes made in this file will be lost!
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing.
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(1060, 587)
MainWindow.resize(1060, 588)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.gridLayout = QtWidgets.QGridLayout(self.centralwidget)
@ -23,7 +26,7 @@ class Ui_MainWindow(object): @@ -23,7 +26,7 @@ class Ui_MainWindow(object):
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, 1060, 19))
self.menubar.setGeometry(QtCore.QRect(0, 0, 1060, 21))
self.menubar.setObjectName("menubar")
self.menuFile = QtWidgets.QMenu(self.menubar)
self.menuFile.setObjectName("menuFile")
@ -69,6 +72,8 @@ class Ui_MainWindow(object): @@ -69,6 +72,8 @@ class Ui_MainWindow(object):
self.actionExecute_in_Portfolio_Mode = QtWidgets.QAction(MainWindow)
self.actionExecute_in_Portfolio_Mode.setIcon(icon2)
self.actionExecute_in_Portfolio_Mode.setObjectName("actionExecute_in_Portfolio_Mode")
self.actionSettings = QtWidgets.QAction(MainWindow)
self.actionSettings.setObjectName("actionSettings")
self.menuFile.addAction(self.actionNew_strategy)
self.menuFile.addAction(self.actionOpen_strategy)
self.menuFile.addAction(self.actionSave_strategy)
@ -85,6 +90,7 @@ class Ui_MainWindow(object): @@ -85,6 +90,7 @@ class Ui_MainWindow(object):
self.toolBar.addSeparator()
self.toolBar.addAction(self.actionExecute)
self.toolBar.addAction(self.actionExecute_in_Portfolio_Mode)
self.toolBar.addAction(self.actionSettings)
self.retranslateUi(MainWindow)
self.tabs.setCurrentIndex(-1)
@ -96,6 +102,7 @@ class Ui_MainWindow(object): @@ -96,6 +102,7 @@ class Ui_MainWindow(object):
self.actionSave_as.triggered.connect(MainWindow.saveStrategyAs)
self.actionPerformance.triggered.connect(MainWindow.performanceAnalysis)
self.actionExecute_in_Portfolio_Mode.triggered.connect(MainWindow.executeStrategyInPortfolioMode)
self.actionSettings.triggered.connect(MainWindow.showSettingsDialog)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
@ -117,5 +124,5 @@ class Ui_MainWindow(object): @@ -117,5 +124,5 @@ class Ui_MainWindow(object):
self.actionSave_as.setText(_translate("MainWindow", "Save as..."))
self.actionPerformance.setText(_translate("MainWindow", "Performance"))
self.actionExecute_in_Portfolio_Mode.setText(_translate("MainWindow", "Execute in Portfolio Mode"))
self.actionSettings.setText(_translate("MainWindow", "Settings"))
import nailab_rc

10
src/nailab/ui_gen/newdatasourcedialog.py

@ -2,12 +2,15 @@ @@ -2,12 +2,15 @@
# Form implementation generated from reading ui file 'ui/newdatasourcedialog.ui'
#
# Created by: PyQt5 UI code generator 5.5.1
# Created by: PyQt5 UI code generator 5.15.1
#
# WARNING! All changes made in this file will be lost!
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing.
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_NewDataSourceDialog(object):
def setupUi(self, NewDataSourceDialog):
NewDataSourceDialog.setObjectName("NewDataSourceDialog")
@ -36,6 +39,7 @@ class Ui_NewDataSourceDialog(object): @@ -36,6 +39,7 @@ class Ui_NewDataSourceDialog(object):
self.cb_sourceType.setSizePolicy(sizePolicy)
self.cb_sourceType.setObjectName("cb_sourceType")
self.cb_sourceType.addItem("")
self.cb_sourceType.addItem("")
self.gridLayout.addWidget(self.cb_sourceType, 1, 1, 1, 1)
self.label_2 = QtWidgets.QLabel(NewDataSourceDialog)
self.label_2.setObjectName("label_2")
@ -56,5 +60,5 @@ class Ui_NewDataSourceDialog(object): @@ -56,5 +60,5 @@ class Ui_NewDataSourceDialog(object):
NewDataSourceDialog.setWindowTitle(_translate("NewDataSourceDialog", "New data source"))
self.label.setText(_translate("NewDataSourceDialog", "Data source type"))
self.cb_sourceType.setItemText(0, _translate("NewDataSourceDialog", "CSV"))
self.cb_sourceType.setItemText(1, _translate("NewDataSourceDialog", "YahooCSV"))
self.label_2.setText(_translate("NewDataSourceDialog", "Data source name"))

10
src/nailab/ui_gen/performancewidget.py

@ -2,12 +2,15 @@ @@ -2,12 +2,15 @@
# Form implementation generated from reading ui file 'ui/performancewidget.ui'
#
# Created by: PyQt5 UI code generator 5.5.1
# Created by: PyQt5 UI code generator 5.15.1
#
# WARNING! All changes made in this file will be lost!
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing.
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_PerformanceWidget(object):
def setupUi(self, PerformanceWidget):
PerformanceWidget.setObjectName("PerformanceWidget")
@ -77,7 +80,7 @@ class Ui_PerformanceWidget(object): @@ -77,7 +80,7 @@ class Ui_PerformanceWidget(object):
self.gridLayout.addWidget(self.lw_strategies, 0, 0, 1, 2)
self.retranslateUi(PerformanceWidget)
self.tab1.setCurrentIndex(1)
self.tab1.setCurrentIndex(0)
self.b_add.clicked.connect(PerformanceWidget.addResults)
self.b_remove.clicked.connect(PerformanceWidget.removeResults)
self.rb_daily.toggled['bool'].connect(PerformanceWidget.dailyToggled)
@ -95,6 +98,5 @@ class Ui_PerformanceWidget(object): @@ -95,6 +98,5 @@ class Ui_PerformanceWidget(object):
self.tab1.setTabText(self.tab1.indexOf(self.tab_2), _translate("PerformanceWidget", "Correlations"))
self.b_add.setText(_translate("PerformanceWidget", "Add..."))
self.b_remove.setText(_translate("PerformanceWidget", "Remove"))
from ui.correlationchartcanvas import CorrelationChartCanvas
from ui.performancecanvas import PerformanceCanvas

51
src/nailab/ui_gen/settingswindow.py

@ -0,0 +1,51 @@ @@ -0,0 +1,51 @@
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'ui/settingswindow.ui'
#
# Created by: PyQt5 UI code generator 5.15.1
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing.
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_SettingsWindow(object):
def setupUi(self, SettingsWindow):
SettingsWindow.setObjectName("SettingsWindow")
SettingsWindow.resize(400, 300)
self.gridLayout = QtWidgets.QGridLayout(SettingsWindow)
self.gridLayout.setObjectName("gridLayout")
spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
self.gridLayout.addItem(spacerItem, 2, 0, 1, 1)
self.sb_commissionPercentage = QtWidgets.QDoubleSpinBox(SettingsWindow)
self.sb_commissionPercentage.setDecimals(4)
self.sb_commissionPercentage.setObjectName("sb_commissionPercentage")
self.gridLayout.addWidget(self.sb_commissionPercentage, 0, 1, 1, 1)
self.label = QtWidgets.QLabel(SettingsWindow)
self.label.setObjectName("label")
self.gridLayout.addWidget(self.label, 0, 0, 1, 1)
self.buttonBox = QtWidgets.QDialogButtonBox(SettingsWindow)
self.buttonBox.setOrientation(QtCore.Qt.Horizontal)
self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok)
self.buttonBox.setObjectName("buttonBox")
self.gridLayout.addWidget(self.buttonBox, 3, 0, 1, 2)
self.label_2 = QtWidgets.QLabel(SettingsWindow)
self.label_2.setObjectName("label_2")
self.gridLayout.addWidget(self.label_2, 1, 0, 1, 1)
self.sb_commissionPerShare = QtWidgets.QDoubleSpinBox(SettingsWindow)
self.sb_commissionPerShare.setDecimals(4)
self.sb_commissionPerShare.setObjectName("sb_commissionPerShare")
self.gridLayout.addWidget(self.sb_commissionPerShare, 1, 1, 1, 1)
self.retranslateUi(SettingsWindow)
self.buttonBox.accepted.connect(SettingsWindow.accept)
self.buttonBox.rejected.connect(SettingsWindow.reject)
QtCore.QMetaObject.connectSlotsByName(SettingsWindow)
def retranslateUi(self, SettingsWindow):
_translate = QtCore.QCoreApplication.translate
SettingsWindow.setWindowTitle(_translate("SettingsWindow", "Settings"))
self.label.setText(_translate("SettingsWindow", "Commission (%)"))
self.label_2.setText(_translate("SettingsWindow", "Commission (per share)"))

62
src/nailab/ui_gen/statisticwidget.py

@ -0,0 +1,62 @@ @@ -0,0 +1,62 @@
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'ui/statisticwidget.ui'
#
# Created by: PyQt5 UI code generator 5.15.1
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing.
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_StatisticWidget(object):
def setupUi(self, StatisticWidget):
StatisticWidget.setObjectName("StatisticWidget")
StatisticWidget.resize(548, 418)
self.gridLayout = QtWidgets.QGridLayout(StatisticWidget)
self.gridLayout.setContentsMargins(1, 1, 1, 1)
self.gridLayout.setObjectName("gridLayout")
self.tabWidget = QtWidgets.QTabWidget(StatisticWidget)
self.tabWidget.setObjectName("tabWidget")
self.tab = QtWidgets.QWidget()
self.tab.setObjectName("tab")
self.gridLayout_2 = QtWidgets.QGridLayout(self.tab)
self.gridLayout_2.setObjectName("gridLayout_2")
self.tw_byTicker = QtWidgets.QTreeWidget(self.tab)
self.tw_byTicker.setObjectName("tw_byTicker")
self.gridLayout_2.addWidget(self.tw_byTicker, 0, 0, 1, 1)
self.tabWidget.addTab(self.tab, "")
self.tab_2 = QtWidgets.QWidget()
self.tab_2.setObjectName("tab_2")
self.gridLayout_3 = QtWidgets.QGridLayout(self.tab_2)
self.gridLayout_3.setObjectName("gridLayout_3")
self.tw_seasonality = QtWidgets.QTreeWidget(self.tab_2)
self.tw_seasonality.setObjectName("tw_seasonality")
self.gridLayout_3.addWidget(self.tw_seasonality, 0, 0, 1, 1)
self.tabWidget.addTab(self.tab_2, "")
self.tab_3 = QtWidgets.QWidget()
self.tab_3.setObjectName("tab_3")
self.tabWidget.addTab(self.tab_3, "")
self.gridLayout.addWidget(self.tabWidget, 0, 0, 1, 1)
self.retranslateUi(StatisticWidget)
self.tabWidget.setCurrentIndex(0)
QtCore.QMetaObject.connectSlotsByName(StatisticWidget)
def retranslateUi(self, StatisticWidget):
_translate = QtCore.QCoreApplication.translate
StatisticWidget.setWindowTitle(_translate("StatisticWidget", "StatisticWidget"))
self.tw_byTicker.setSortingEnabled(True)
self.tw_byTicker.headerItem().setText(0, _translate("StatisticWidget", "Ticker"))
self.tw_byTicker.headerItem().setText(1, _translate("StatisticWidget", "Net profit"))
self.tw_byTicker.headerItem().setText(2, _translate("StatisticWidget", "Total trades"))
self.tw_byTicker.headerItem().setText(3, _translate("StatisticWidget", "Avg. return"))
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab), _translate("StatisticWidget", "By ticker"))
self.tw_seasonality.setSortingEnabled(True)
self.tw_seasonality.headerItem().setText(1, _translate("StatisticWidget", "Net profit"))
self.tw_seasonality.headerItem().setText(2, _translate("StatisticWidget", "Total trades"))
self.tw_seasonality.headerItem().setText(3, _translate("StatisticWidget", "Avg. return"))
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_2), _translate("StatisticWidget", "Seasonal"))
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_3), _translate("StatisticWidget", "Returns"))

29
src/nailab/ui_gen/strategywidget.py

@ -2,16 +2,19 @@ @@ -2,16 +2,19 @@
# Form implementation generated from reading ui file 'ui/strategywidget.ui'
#
# Created by: PyQt5 UI code generator 5.5.1
# Created by: PyQt5 UI code generator 5.15.1
#
# WARNING! All changes made in this file will be lost!
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing.
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_StrategyWidget(object):
def setupUi(self, StrategyWidget):
StrategyWidget.setObjectName("StrategyWidget")
StrategyWidget.resize(977, 569)
StrategyWidget.resize(977, 666)
self.gridLayout_3 = QtWidgets.QGridLayout(StrategyWidget)
self.gridLayout_3.setContentsMargins(1, 1, 1, 1)
self.gridLayout_3.setObjectName("gridLayout_3")
@ -28,6 +31,7 @@ class Ui_StrategyWidget(object): @@ -28,6 +31,7 @@ class Ui_StrategyWidget(object):
self.gridLayoutWidget = QtWidgets.QWidget(self.splitter)
self.gridLayoutWidget.setObjectName("gridLayoutWidget")
self.gridLayout_2 = QtWidgets.QGridLayout(self.gridLayoutWidget)
self.gridLayout_2.setContentsMargins(2, 2, 2, 2)
self.gridLayout_2.setObjectName("gridLayout_2")
self.horizontalLayout = QtWidgets.QHBoxLayout()
self.horizontalLayout.setObjectName("horizontalLayout")
@ -44,16 +48,16 @@ class Ui_StrategyWidget(object): @@ -44,16 +48,16 @@ class Ui_StrategyWidget(object):
self.b_deleteSource = QtWidgets.QPushButton(self.gridLayoutWidget)
self.b_deleteSource.setObjectName("b_deleteSource")
self.horizontalLayout.addWidget(self.b_deleteSource)
self.gridLayout_2.addLayout(self.horizontalLayout, 5, 0, 1, 2)
self.dte_to = QtWidgets.QDateTimeEdit(self.gridLayoutWidget)
self.dte_to.setObjectName("dte_to")
self.gridLayout_2.addWidget(self.dte_to, 3, 1, 1, 1)
self.gridLayout_2.addLayout(self.horizontalLayout, 7, 0, 1, 2)
self.dte_from = QtWidgets.QDateTimeEdit(self.gridLayoutWidget)
self.dte_from.setObjectName("dte_from")
self.gridLayout_2.addWidget(self.dte_from, 2, 1, 1, 1)
self.gridLayout_2.addWidget(self.dte_from, 4, 1, 1, 1)
self.label_2 = QtWidgets.QLabel(self.gridLayoutWidget)
self.label_2.setObjectName("label_2")
self.gridLayout_2.addWidget(self.label_2, 3, 0, 1, 1)
self.gridLayout_2.addWidget(self.label_2, 5, 0, 1, 1)
self.dte_to = QtWidgets.QDateTimeEdit(self.gridLayoutWidget)
self.dte_to.setObjectName("dte_to")
self.gridLayout_2.addWidget(self.dte_to, 5, 1, 1, 1)
self.rb_allData = QtWidgets.QRadioButton(self.gridLayoutWidget)
self.rb_allData.setChecked(True)
self.rb_allData.setObjectName("rb_allData")
@ -69,7 +73,7 @@ class Ui_StrategyWidget(object): @@ -69,7 +73,7 @@ class Ui_StrategyWidget(object):
self.tw_feeds.setHeaderHidden(True)
self.tw_feeds.setObjectName("tw_feeds")
self.tw_feeds.headerItem().setText(0, "1")
self.gridLayout_2.addWidget(self.tw_feeds, 4, 0, 1, 2)
self.gridLayout_2.addWidget(self.tw_feeds, 6, 0, 1, 2)
self.label = QtWidgets.QLabel(self.gridLayoutWidget)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Preferred)
sizePolicy.setHorizontalStretch(0)
@ -77,7 +81,7 @@ class Ui_StrategyWidget(object): @@ -77,7 +81,7 @@ class Ui_StrategyWidget(object):
sizePolicy.setHeightForWidth(self.label.sizePolicy().hasHeightForWidth())
self.label.setSizePolicy(sizePolicy)
self.label.setObjectName("label")
self.gridLayout_2.addWidget(self.label, 2, 0, 1, 1)
self.gridLayout_2.addWidget(self.label, 4, 0, 1, 1)
self.rb_timeWindow = QtWidgets.QRadioButton(self.gridLayoutWidget)
self.rb_timeWindow.setObjectName("rb_timeWindow")
self.gridLayout_2.addWidget(self.rb_timeWindow, 1, 0, 1, 2)
@ -111,12 +115,11 @@ class Ui_StrategyWidget(object): @@ -111,12 +115,11 @@ class Ui_StrategyWidget(object):
self.b_addSource.setText(_translate("StrategyWidget", "Add source"))
self.b_refresh.setText(_translate("StrategyWidget", "Refresh"))
self.b_deleteSource.setText(_translate("StrategyWidget", "Delete source"))
self.dte_to.setDisplayFormat(_translate("StrategyWidget", "dd.MM.yyyy H:mm"))
self.dte_from.setDisplayFormat(_translate("StrategyWidget", "dd.MM.yyyy H:mm"))
self.label_2.setText(_translate("StrategyWidget", "To"))
self.dte_to.setDisplayFormat(_translate("StrategyWidget", "dd.MM.yyyy H:mm"))
self.rb_allData.setText(_translate("StrategyWidget", "All data"))
self.label.setText(_translate("StrategyWidget", "From"))
self.rb_timeWindow.setText(_translate("StrategyWidget", "Time window"))
self.tabs.setTabText(self.tabs.indexOf(self.tab), _translate("StrategyWidget", "Code"))
from PyQt5 import Qsci

8
src/nailab/ui_gen/tradeslistwidget.py

@ -2,12 +2,15 @@ @@ -2,12 +2,15 @@
# Form implementation generated from reading ui file 'ui/tradeslistwidget.ui'
#
# Created by: PyQt5 UI code generator 5.5.1
# Created by: PyQt5 UI code generator 5.15.1
#
# WARNING! All changes made in this file will be lost!
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing.
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_TradesListWidget(object):
def setupUi(self, TradesListWidget):
TradesListWidget.setObjectName("TradesListWidget")
@ -40,4 +43,3 @@ class Ui_TradesListWidget(object): @@ -40,4 +43,3 @@ class Ui_TradesListWidget(object):
self.trades.headerItem().setText(5, _translate("TradesListWidget", "Exit time"))
self.trades.headerItem().setText(6, _translate("TradesListWidget", "Exit price"))
self.trades.headerItem().setText(7, _translate("TradesListWidget", "PnL"))

27
ui/mainwindow.ui

@ -7,7 +7,7 @@ @@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>1060</width>
<height>587</height>
<height>588</height>
</rect>
</property>
<property name="windowTitle">
@ -45,7 +45,7 @@ @@ -45,7 +45,7 @@
<x>0</x>
<y>0</y>
<width>1060</width>
<height>19</height>
<height>21</height>
</rect>
</property>
<widget class="QMenu" name="menuFile">
@ -91,6 +91,7 @@ @@ -91,6 +91,7 @@
<addaction name="separator"/>
<addaction name="actionExecute"/>
<addaction name="actionExecute_in_Portfolio_Mode"/>
<addaction name="actionSettings"/>
</widget>
<action name="actionOpenTrades">
<property name="text">
@ -166,6 +167,11 @@ @@ -166,6 +167,11 @@
<string>Execute in Portfolio Mode</string>
</property>
</action>
<action name="actionSettings">
<property name="text">
<string>Settings</string>
</property>
</action>
</widget>
<resources>
<include location="../nailab.qrc"/>
@ -299,6 +305,22 @@ @@ -299,6 +305,22 @@
</hint>
</hints>
</connection>
<connection>
<sender>actionSettings</sender>
<signal>triggered()</signal>
<receiver>MainWindow</receiver>
<slot>showSettingsDialog()</slot>
<hints>
<hint type="sourcelabel">
<x>-1</x>
<y>-1</y>
</hint>
<hint type="destinationlabel">
<x>529</x>
<y>293</y>
</hint>
</hints>
</connection>
</connections>
<slots>
<slot>openTrades()</slot>
@ -310,5 +332,6 @@ @@ -310,5 +332,6 @@
<slot>saveStrategyAs()</slot>
<slot>performanceAnalysis()</slot>
<slot>executeStrategyInPortfolioMode()</slot>
<slot>showSettingsDialog()</slot>
</slots>
</ui>

5
ui/newdatasourcedialog.ui

@ -50,6 +50,11 @@ @@ -50,6 +50,11 @@
<string>CSV</string>
</property>
</item>
<item>
<property name="text">
<string>YahooCSV</string>
</property>
</item>
</widget>
</item>
<item row="0" column="0">

2
ui/performancewidget.ui

@ -29,7 +29,7 @@ @@ -29,7 +29,7 @@
<item row="0" column="2">
<widget class="QTabWidget" name="tab1">
<property name="currentIndex">
<number>1</number>
<number>0</number>
</property>
<widget class="QWidget" name="tab">
<attribute name="title">

105
ui/settingswindow.ui

@ -0,0 +1,105 @@ @@ -0,0 +1,105 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>SettingsWindow</class>
<widget class="QDialog" name="SettingsWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>Settings</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="2" column="0">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="1">
<widget class="QDoubleSpinBox" name="sb_commissionPercentage">
<property name="decimals">
<number>4</number>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Commission (%)</string>
</property>
</widget>
</item>
<item row="3" column="0" colspan="2">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Commission (per share)</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QDoubleSpinBox" name="sb_commissionPerShare">
<property name="decimals">
<number>4</number>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>SettingsWindow</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>SettingsWindow</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

113
ui/statisticwidget.ui

@ -0,0 +1,113 @@ @@ -0,0 +1,113 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>StatisticWidget</class>
<widget class="QWidget" name="StatisticWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>548</width>
<height>418</height>
</rect>
</property>
<property name="windowTitle">
<string>StatisticWidget</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<property name="leftMargin">
<number>1</number>
</property>
<property name="topMargin">
<number>1</number>
</property>
<property name="rightMargin">
<number>1</number>
</property>
<property name="bottomMargin">
<number>1</number>
</property>
<item row="0" column="0">
<widget class="QTabWidget" name="tabWidget">
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="tab">
<attribute name="title">
<string>By ticker</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<widget class="QTreeWidget" name="tw_byTicker">
<property name="sortingEnabled">
<bool>true</bool>
</property>
<column>
<property name="text">
<string>Ticker</string>
</property>
</column>
<column>
<property name="text">
<string>Net profit</string>
</property>
</column>
<column>
<property name="text">
<string>Total trades</string>
</property>
</column>
<column>
<property name="text">
<string>Avg. return</string>
</property>
</column>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_2">
<attribute name="title">
<string>Seasonal</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="0">
<widget class="QTreeWidget" name="tw_seasonality">
<property name="sortingEnabled">
<bool>true</bool>
</property>
<column>
<property name="text">
<string/>
</property>
</column>
<column>
<property name="text">
<string>Net profit</string>
</property>
</column>
<column>
<property name="text">
<string>Total trades</string>
</property>
</column>
<column>
<property name="text">
<string>Avg. return</string>
</property>
</column>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_3">
<attribute name="title">
<string>Returns</string>
</attribute>
</widget>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

38
ui/strategywidget.ui

@ -7,7 +7,7 @@ @@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>977</width>
<height>569</height>
<height>666</height>
</rect>
</property>
<property name="windowTitle">
@ -55,7 +55,19 @@ @@ -55,7 +55,19 @@
</property>
<widget class="QWidget" name="gridLayoutWidget">
<layout class="QGridLayout" name="gridLayout_2">
<item row="5" column="0" colspan="2">
<property name="leftMargin">
<number>2</number>
</property>
<property name="topMargin">
<number>2</number>
</property>
<property name="rightMargin">
<number>2</number>
</property>
<property name="bottomMargin">
<number>2</number>
</property>
<item row="7" column="0" colspan="2">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QPushButton" name="b_addSource">
@ -106,27 +118,27 @@ @@ -106,27 +118,27 @@
</item>
</layout>
</item>
<item row="3" column="1">
<widget class="QDateTimeEdit" name="dte_to">
<property name="displayFormat">
<string>dd.MM.yyyy H:mm</string>
</property>
</widget>
</item>
<item row="2" column="1">
<item row="4" column="1">
<widget class="QDateTimeEdit" name="dte_from">
<property name="displayFormat">
<string>dd.MM.yyyy H:mm</string>
</property>
</widget>
</item>
<item row="3" column="0">
<item row="5" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>To</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QDateTimeEdit" name="dte_to">
<property name="displayFormat">
<string>dd.MM.yyyy H:mm</string>
</property>
</widget>
</item>
<item row="0" column="0" colspan="2">
<widget class="QRadioButton" name="rb_allData">
<property name="text">
@ -137,7 +149,7 @@ @@ -137,7 +149,7 @@
</property>
</widget>
</item>
<item row="4" column="0" colspan="2">
<item row="6" column="0" colspan="2">
<widget class="QTreeWidget" name="tw_feeds">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
@ -161,7 +173,7 @@ @@ -161,7 +173,7 @@
</column>
</widget>
</item>
<item row="2" column="0">
<item row="4" column="0">
<widget class="QLabel" name="label">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">

Loading…
Cancel
Save