Browse Source

Work (yes)

master
Denis Tereshkin 4 years ago
parent
commit
1673e6f693
  1. 2
      cuda/__init__.py
  2. 72
      cuda/signalcalc.py
  3. 234
      data/signal.py
  4. 66
      execution/executor.py
  5. 110
      solver/cudasolver.py
  6. 46
      solver/solver.py
  7. 28
      ui/mainwindow.py
  8. 34
      ui/mainwindow.ui
  9. 18
      ui/ui_mainwindow.py

2
cuda/__init__.py

@ -0,0 +1,2 @@ @@ -0,0 +1,2 @@
'''
'''

72
cuda/signalcalc.py

@ -0,0 +1,72 @@ @@ -0,0 +1,72 @@
'''
'''
import pycuda.driver as cuda
import pycuda.autoinit
from pycuda.compiler import SourceModule
class SignalCalculator():
'''
'''
def __init__(self):
'''
'''
self.generators = []
def add_signal_generator(self, gen):
self.generators.append(gen)
def make_cuda_kernel(self):
src = """
#include <curand_kernel.h>
const int nstates = %(NGENERATORS)s;
__device__ curandState_t* states[nstates];
__global__ void initkernel(int seed)
{
int tidx = threadIdx.x + blockIdx.x * blockDim.x;
if (tidx < nstates) {
curandState_t* s = new curandState_t;
if (s != 0) {
curand_init(seed, tidx, 0, s);
}
states[tidx] = s;
}
}
__global__ void calc_signal(float* open, float* high, float* low, float* close, size_t points, int8_t* signals, char* sig_names, float* scratch)
{
int tidx = threadIdx.x + blockIdx.x * blockDim.x;
curandState_t s = *states[tidx];
int signals = 5 * curand_uniform(&s);
float* tScratch = &scratch[tidx * points];
int8_t* tSignals = &signals[tidx * points];
char* tSigName = &signames[tidx * 256];
for(int i = 0; i < signals; i++)
{
int sigtype = curand_uniform(&s);
switch(sigtype)
{
"""
i = 0
for gen in self.generators:
src += gen.make_signal_kernel(i)
i += 1
src += """
}
}
}
"""

234
data/signal.py

@ -5,7 +5,6 @@ import random @@ -5,7 +5,6 @@ import random
import numpy
import talib
from scipy.integrate.tests.test_odeint_jac import rhs
class Signal:
@ -21,6 +20,9 @@ class Signal: @@ -21,6 +20,9 @@ class Signal:
def mutate(self, factor):
return copy.deepcopy(self)
def cuda_kernel(self):
pass
class PriceComparisonSignalGenerator:
def __init__(self):
@ -36,6 +38,54 @@ class PriceComparisonSignalGenerator: @@ -36,6 +38,54 @@ class PriceComparisonSignalGenerator:
def id(self):
return 'Price'
def make_signal_kernel(self, ix):
return ("""
case %(IX):
{
int lhs = curand_uniform(&s) * 4;
int rhs = curand_uniform(&s) * 4;
int lhs_shift = curand_uniform(&s) * 10;
int rhs_shift = curand_uniform(&s) * 10;
float* lx = open;
if(lhs == 1)
{
lx = high;
}
else if(lhs == 2)
{
lx = low;
}
else if(lhs == 3)
{
lx = close;
}
float* rx = open;
if(rhs == 1)
{
rx = high;
}
else if(rhs == 2)
{
rx = low;
}
else if(rhs == 3)
{
rx = close;
}
for(int x = 0; x < points; x++)
{
if((x < lhs_shift) || (x < rhs_shift))
{
tSignals[x] = 0;
}
else
{
tSignals[x] &= (lx[x - lhs_shift] < rx[x - rhs_shift]);
}
}
}
""")
class PriceComparisonSignal(Signal):
OPEN = 0
@ -50,9 +100,9 @@ class PriceComparisonSignal(Signal): @@ -50,9 +100,9 @@ class PriceComparisonSignal(Signal):
self.rhs_shift = rhs_shift
def calculate(self, series):
result = []
result = numpy.zeros(series.length())
for i in range(0, series.length()):
result.append(self.calculate_at_index(series, i))
result[i] = self.calculate_at_index(series, i)
return result
@ -110,9 +160,7 @@ class PriceComparisonSignal(Signal): @@ -110,9 +160,7 @@ class PriceComparisonSignal(Signal):
self.lhs_shift = max(0, self.lhs_shift + random.randint(-int(10 * factor + 1), int(10 * factor + 1)))
elif mutation_type == 3:
self.rhs_shift = max(0, self.rhs_shift + random.randint(-int(10 * factor + 1), int(10 * factor + 1)))
class RsiSignalGenerator:
def __init__(self):
@ -148,11 +196,13 @@ class RsiSignal(Signal): @@ -148,11 +196,13 @@ class RsiSignal(Signal):
rsi = talib.RSI(closes, self.period)
result = [self.calc_signal(v) for v in rsi]
if self.shift == 0:
return result
else:
return [False] * self.shift + result[:-self.shift]
result = numpy.zeros(len(rsi))
pos = 0
for i in range(self.shift, len(result)):
result[i] = self.calc_signal(rsi[pos])
pos += 1
return result
def calc_signal(self, value):
if self.inequality_type == RsiSignal.LT:
@ -205,9 +255,11 @@ class AtrSignal(Signal): @@ -205,9 +255,11 @@ class AtrSignal(Signal):
highs = numpy.array([series.get_high(i) for i in range(0, series.length())])
lows = numpy.array([series.get_low(i) for i in range(0, series.length())])
atr = talib.ATR(highs, lows, closes, self.period)
atr = numpy.nan_to_num(talib.ATR(highs, lows, closes, self.period))
result = [self.calc_signal(v, c) for (v, c) in zip(atr, closes)]
result = numpy.zeros(len(atr))
for i in range(0, len(atr)):
result[i] = self.calc_signal(atr[i], closes[i])
return result
def calc_signal(self, value, close):
@ -271,13 +323,12 @@ class AtrDeltaSignal(Signal): @@ -271,13 +323,12 @@ class AtrDeltaSignal(Signal):
highs = numpy.array([series.get_high(i) for i in range(0, series.length())])
lows = numpy.array([series.get_low(i) for i in range(0, series.length())])
atr = talib.ATR(highs, lows, closes, self.period)
atr = numpy.nan_to_num(talib.ATR(highs, lows, closes, self.period))
result = [False]
result = numpy.zeros(len(atr))
for i in range(1, len(closes)):
result.append(self.calc_signal(atr[i], closes[i], closes[i - 1]))
result[i] = self.calc_signal(atr[i], closes[i], closes[i - 1])
return result
def calc_signal(self, value, c1, c2):
@ -324,9 +375,9 @@ class DayOfWeekSignal(Signal): @@ -324,9 +375,9 @@ class DayOfWeekSignal(Signal):
self.day_of_week = day_of_week
def calculate(self, series):
result = []
result = numpy.zeros(series.length())
for i in range(0, series.length()):
result.append(series.get_dt(i).date().weekday() == self.day_of_week)
result[i] = series.get_dt(i).date().weekday() == self.day_of_week
return result
@ -367,12 +418,12 @@ class DayOfMonthSignal(Signal): @@ -367,12 +418,12 @@ class DayOfMonthSignal(Signal):
self.inequality_sign_str = '>'
def calculate(self, series):
result = []
result = numpy.zeros(series.length())
for i in range(0, series.length()):
if self.inequality_type == DayOfMonthSignal.LT:
result.append(series.get_dt(i).date().day < self.day_of_month)
result[i] = series.get_dt(i).date().day < self.day_of_month
else:
result.append(series.get_dt(i).date().day > self.day_of_month)
result[i] = series.get_dt(i).date().day > self.day_of_month
return result
@ -412,7 +463,7 @@ class CrtdrSignal(Signal): @@ -412,7 +463,7 @@ class CrtdrSignal(Signal):
self.inequality_sign_str = '>'
def calculate(self, series):
result = []
result = numpy.zeros(series.length())
for i in range(0, series.length()):
try:
h = series.get_high(i - self.shift)
@ -421,13 +472,13 @@ class CrtdrSignal(Signal): @@ -421,13 +472,13 @@ class CrtdrSignal(Signal):
if h > l:
if self.inequality_type == CrtdrSignal.LT:
result.append((c - l) / (h - l) < self.threshold)
result[i] = (c - l) / (h - l) < self.threshold
else:
result.append((c - l) / (h - l) > self.threshold)
result[i] = (c - l) / (h - l) > self.threshold
else:
result.append(False)
result[i] = False
except IndexError:
result.append(False)
result[i] = False
return result
@ -498,9 +549,11 @@ class SmaSignal(Signal): @@ -498,9 +549,11 @@ class SmaSignal(Signal):
elif self.rhs == SmaSignal.CLOSE:
rhs = numpy.array([series.get_close(i) for i in range(0, series.length())])
rhs_sma = talib.SMA(rhs, self.period)
rhs_sma = numpy.nan_to_num(talib.SMA(rhs, self.period))
result = [self.calc_signal(l, r) for (l, r) in zip(lhs, rhs_sma)]
result = numpy.zeros(series.length())
for i in range(0, len(result)):
result[i] = self.calc_signal(lhs[i], rhs_sma[i])
return result
def calc_signal(self, l, r):
@ -560,14 +613,15 @@ class CciSignal(Signal): @@ -560,14 +613,15 @@ class CciSignal(Signal):
highs = numpy.array([series.get_high(i) for i in range(0, series.length())])
lows = numpy.array([series.get_low(i) for i in range(0, series.length())])
cci = talib.CCI(highs, lows, closes, self.period)
result = [self.calc_signal(v) for v in cci]
cci = numpy.nan_to_num(talib.CCI(highs, lows, closes, self.period))
if self.shift == 0:
return result
else:
return [False] * self.shift + result[:-self.shift]
result = numpy.zeros(len(cci))
pos = 0
for i in range(self.shift, len(result)):
result[i] = cci[pos]
pos += 1
return result
def calc_signal(self, value):
if self.inequality_type == CciSignal.LT:
@ -655,16 +709,16 @@ class BbandsSignal(Signal): @@ -655,16 +709,16 @@ class BbandsSignal(Signal):
elif self.rhs == BbandsSignal.CLOSE:
rhs = numpy.array([series.get_close(i) for i in range(0, series.length())])
(upband, _, downband) = talib.BBANDS(rhs, self.period, self.dev, self.dev)
(downband, _, upband) = talib.BBANDS(rhs, self.period, self.dev, self.dev)
if self.band_type == BbandsSignal.UP:
band = upband
band = numpy.nan_to_num(upband)
else:
band = downband
result = [self.calc_signal(l, r) for (l, r) in zip(lhs, band)]
band = numpy.nan_to_num(downband)
result = numpy.zeros(len(band))
for i in range(0, len(result)):
result[i] = self.calc_signal(lhs[i], band[i])
return result
def calc_signal(self, l, r):
@ -727,14 +781,12 @@ class PivotPointsSignal(Signal): @@ -727,14 +781,12 @@ class PivotPointsSignal(Signal):
self.rhs_shift = rhs_shift
def calculate(self, series):
result = []
result = numpy.zeros(series.length())
for i in range(0, series.length()):
lhs = self.calculate_signal(series, self.lhs, i - self.lhs_shift)
rhs = self.calculate_signal(series, self.rhs, i - self.rhs_shift)
if i - self.lhs_shift >= 0 and i - self.rhs_shift >= 0:
result.append(lhs < rhs)
else:
result.append(False)
result[i] = lhs < rhs
return result
@ -836,11 +888,17 @@ class StochasticSignal(Signal): @@ -836,11 +888,17 @@ class StochasticSignal(Signal):
stoch_k, stoch_d = talib.STOCHF(highs, lows, closes, self.period, self.period2)
result = [self.calc_signal(v) for v in stoch_k]
if self.shift == 0:
return result
else:
return [False] * self.shift + result[:-self.shift]
stoch_k = numpy.nan_to_num(stoch_k)
result = numpy.zeros(len(stoch_k))
pos = 0
for i in range(self.shift, len(result)):
result[i] = self.calc_signal(stoch_k[pos])
pos += 1
return result
def calc_signal(self, value):
if self.inequality_type == StochasticSignal.LT:
@ -849,7 +907,7 @@ class StochasticSignal(Signal): @@ -849,7 +907,7 @@ class StochasticSignal(Signal):
return value > self.threshold
def get_text(self):
return "stoch(c, {:d})[{:d}] {:s} {:d}".format(self.period, self.shift, self.inequality_sign_str, int(self.threshold))
return "stoch(c, {:d}, {:d})[{:d}] {:s} {:d}".format(self.period, self.period2, self.shift, self.inequality_sign_str, int(self.threshold))
class IntradayBarNumberSignalGenerator:
@ -882,7 +940,7 @@ class IntradayBarNumberSignal(Signal): @@ -882,7 +940,7 @@ class IntradayBarNumberSignal(Signal):
self.inequality_sign_str = '=='
def calculate(self, series):
ibn = []
ibn = numpy.zeros(series.length())
cur_date = None
for i in range(0, series.length()):
if series.get_dt(i).date() != cur_date:
@ -890,11 +948,11 @@ class IntradayBarNumberSignal(Signal): @@ -890,11 +948,11 @@ class IntradayBarNumberSignal(Signal):
ctr = 0
else:
ctr += 1
ibn.append(ctr)
ibn[i] = ctr
result = []
for i in ibn:
result.append(self.calc_signal(i))
result = numpy.zeros(len(ibn))
for i in range(0, len(result)):
result[i] = self.calc_signal(ibn[i])
return result
def calc_signal(self, ibn):
@ -907,4 +965,64 @@ class IntradayBarNumberSignal(Signal): @@ -907,4 +965,64 @@ class IntradayBarNumberSignal(Signal):
def get_text(self):
return "ibn {:s} {:d}".format(self.inequality_sign_str, self.ibn)
class GainPercentrankSignalGenerator:
def __init__(self):
pass
def generate(self):
period = random.randint(2, 120)
threshold = random.choice([1, 5, 10, 20, 25, 50, 75, 80, 90, 95, 99])
ineq_type = random.randint(GainPercentrankSignal.LT, GainPercentrankSignal.GT)
return GainPercentrankSignal(period, threshold, ineq_type)
def id(self):
return 'IBN'
class GainPercentrankSignal(Signal):
LT = 0
GT = 1
def __init__(self, period, threshold, inequality_type):
self.period = period
self.threshold = threshold
self.inequality_type = inequality_type
if inequality_type == GainPercentrankSignal.LT:
self.inequality_sign_str = '<'
elif inequality_type == GainPercentrankSignal.GT:
self.inequality_sign_str = '>'
else:
self.inequality_sign_str = '=='
def calculate(self, series):
gains = numpy.zeros(series.length())
for i in range(0, len(gains)):
gains[i] = series.get_close(i) / series.get_open(i)
result = numpy.zeros(series.length())
for i in range(0, len(result)):
result[i] = self.calc_signal(gains[i-self.period+1:i+1])
return result
def calc_signal(self, gains):
if len(gains) == 0:
return False
current_gain = gains[-1]
less = 1
for g in gains:
if g < current_gain:
less += 1
rank = 100 * (float(less) / len(gains))
if self.inequality_type == GainPercentrankSignal.LT:
return rank < self.threshold
elif self.inequality_type == GainPercentrankSignal.GT:
return rank > self.threshold
def get_text(self):
return "%rank(return, {:d}) {:s} {:d}".format(self.period, self.inequality_sign_str, self.threshold)

66
execution/executor.py

@ -2,6 +2,7 @@ @@ -2,6 +2,7 @@
'''
from .trade import Trade
import numpy
class Executor(object):
'''
@ -15,44 +16,59 @@ class Executor(object): @@ -15,44 +16,59 @@ class Executor(object):
self.series = series
self.max_hold_bars = max_hold_bars
def execute(self, signals, long=True):
def execute(self, sig_vectors, long=True, stop=None, tp=None):
self.trades = []
sig_vectors = []
vec_length = 0
for signal in signals:
vec = signal.calculate(self.series)
sig_vectors.append(vec)
if vec_length == 0:
vec_length = len(vec)
else:
assert(vec_length == len(vec))
in_trade = False
current_entry_price = None
bar_counter = 0
entry_bar = 0
stop_price = 0
tp_price = 0
for i in range(0, vec_length):
for i in range(0, self.series.length()):
if not in_trade:
has_signal = True
for vec in sig_vectors:
if vec[i] is None or vec[i] == False:
has_signal = False
break
has_signal = sig_vectors[i]
if has_signal and i + 1 < vec_length:
if has_signal and i + 1 < self.series.length():
in_trade = True
current_entry_price = self.series.get_open(i + 1)
if stop is not None:
if long:
stop_price = current_entry_price * (1 - stop)
else:
stop_price = current_entry_price * (1 + stop)
if tp is not None:
if long:
tp_price = current_entry_price * (1 + tp)
else:
tp_price = current_entry_price * (1 - tp)
entry_bar = i + 1
bar_counter = 0
else:
bar_counter += 1
if bar_counter >= self.max_hold_bars:
in_trade = False
if long:
trade_dir = Trade.LONG
else:
trade_dir = Trade.SHORT
self.trades.append(Trade(current_entry_price, self.series.get_close(i), entry_bar, i, trade_dir))
if long:
if stop is not None and self.series.get_low(i) < stop_price:
self.trades.append(Trade(current_entry_price, stop_price, entry_bar, i, Trade.LONG))
in_trade = False
elif tp is not None and self.series.get_high(i) > tp_price:
self.trades.append(Trade(current_entry_price, tp_price, entry_bar, i, Trade.LONG))
in_trade = False
else:
if stop is not None and self.series.get_high(i) > stop_price:
self.trades.append(Trade(current_entry_price, stop_price, entry_bar, i, Trade.SHORT))
in_trade = False
elif tp is not None and self.series.get_low(i) < tp_price:
self.trades.append(Trade(current_entry_price, tp_price, entry_bar, i, Trade.SHORT))
in_trade = False
if in_trade:
if bar_counter >= self.max_hold_bars:
in_trade = False
if long:
trade_dir = Trade.LONG
else:
trade_dir = Trade.SHORT
self.trades.append(Trade(current_entry_price, self.series.get_close(i), entry_bar, i, trade_dir))
return self.trades

110
solver/cudasolver.py

@ -0,0 +1,110 @@ @@ -0,0 +1,110 @@
'''
'''
from PyQt5.Qt import pyqtSignal
from PyQt5 import QtCore
import random
class CudaSolver():
'''
'''
progress = pyqtSignal(int, int, name='progress')
done = pyqtSignal(list, name='done')
def __init__(self, calc, series):
'''
Constructor
'''
super().__init__(None)
self.calc = calc
self.series = series
self.generators = []
self.counter = 0
self.total_counter = 0
def add_generator(self, generator):
self.generators.append(generator)
@QtCore.pyqtSlot(dict)
def solve(self, params):
max_signals = 5
max_hold_bars = params.get('max_hold_bars', 1)
#self.executor = Executor(self.series, max_hold_bars)
max_strategies = params.get('num_strategies', 1000)
results = []
min_trades = params.get('min_trades', 0)
min_win_rate = params.get('min_win_rate', 0)
min_sharpe = params.get('min_sharpe', 0)
stop = params.get('stop_loss', None)
tp = params.get('take_profit', None)
is_long = params.get('direction', 'long') == 'long'
while len(results) < max_strategies:
sig_num = random.randint(1, max_signals)
strategy = []
for i in range(0, sig_num):
strategy.append(random.choice(self.generators).generate())
trades = self.executor.execute(strategy, is_long, stop, tp)
if len(trades) >= min_trades:
result = self.evaluate_trades(trades)
if result['win_percentage'] > min_win_rate and result['sharpe'] > min_sharpe:
result['strategy'] = strategy
result['display_name'] = ' && '.join([signal.get_text() for signal in strategy])
result['trades'] = trades
results.append(result)
self.progress.emit(len(results), max_strategies)
self.done.emit([result])
self.counter += 1
self.total_counter += 1
def evaluate_trades(self, trades):
result = {}
profits = [x.pnl() for x in trades]
total_won = len(list(filter(lambda x: x.pnl() > 0, trades)))
if len(trades) > 0:
result['win_percentage'] = total_won / len(trades) * 100
else:
result['win_percentage'] = 0
result['trades_number'] = len(trades)
result['total_pnl'] = sum(profits)
if len(trades) > 0:
result['avg_percentage'] = sum([trade.pnl_percentage() for trade in trades]) / len(trades)
else:
result['avg_percentage'] = 0
gross_profit = sum([max(0, x.pnl()) for x in trades])
gross_loss = sum([min(0, x.pnl()) for x in trades])
if gross_loss != 0:
result['profit_factor'] = gross_profit / (-gross_loss)
else:
result['profit_factor'] = inf
if len(profits) > 0:
mean = numpy.mean(profits)
stddev = numpy.std(profits)
if stddev != 0:
result['sharpe'] = mean / stddev
else:
result['sharpe'] = 0
else:
result['sharpe'] = 0
return result

46
solver/solver.py

@ -9,6 +9,9 @@ import numpy @@ -9,6 +9,9 @@ import numpy
from PyQt5.Qt import pyqtSignal, QObject
from PyQt5 import QtCore
import talib
from data.signal import PriceComparisonSignal, DayOfMonthSignal, DayOfWeekSignal,\
StochasticSignal, IntradayBarNumberSignal, BbandsSignal,\
GainPercentrankSignal
class Solver(QObject):
'''
@ -26,12 +29,15 @@ class Solver(QObject): @@ -26,12 +29,15 @@ class Solver(QObject):
self.series = series
self.generators = []
self.counter = 0
self.total_counter = 0
def add_generator(self, generator):
self.generators.append(generator)
@QtCore.pyqtSlot(dict)
def solve(self, params):
def solve(self, params):
max_signals = 5
max_hold_bars = params.get('max_hold_bars', 1)
self.executor = Executor(self.series, max_hold_bars)
@ -42,15 +48,33 @@ class Solver(QObject): @@ -42,15 +48,33 @@ class Solver(QObject):
min_win_rate = params.get('min_win_rate', 0)
min_sharpe = params.get('min_sharpe', 0)
stop = params.get('stop_loss', None)
tp = params.get('take_profit', None)
is_long = params.get('direction', 'long') == 'long'
print(is_long)
strategy = [GainPercentrankSignal(107, 1, GainPercentrankSignal.LT)]
signals = self.make_signals(strategy)
trades = self.executor.execute(signals, is_long, stop, tp)
result = self.evaluate_trades(trades)
result['strategy'] = strategy
result['display_name'] = ' && '.join([signal.get_text() for signal in strategy])
result['trades'] = trades
results.append(result)
self.progress.emit(len(results), max_strategies)
self.done.emit([result])
while len(results) < max_strategies:
sig_num = random.randint(1, max_signals)
strategy = []
for i in range(0, sig_num):
strategy.append(random.choice(self.generators).generate())
trades = self.executor.execute(strategy, is_long)
signals = self.make_signals(strategy)
trades = self.executor.execute(signals, is_long, stop, tp)
if len(trades) >= min_trades:
result = self.evaluate_trades(trades)
if result['win_percentage'] > min_win_rate and result['sharpe'] > min_sharpe:
@ -59,8 +83,20 @@ class Solver(QObject): @@ -59,8 +83,20 @@ class Solver(QObject):
result['trades'] = trades
results.append(result)
self.progress.emit(len(results), max_strategies)
self.done.emit([result])
self.counter += 1
self.total_counter += 1
self.done.emit(results)
def make_signals(self, strategy):
sig_vectors = numpy.ones(self.series.length(), dtype=int)
for signal in strategy:
vec = signal.calculate(self.series)
assert(len(vec) == self.series.length())
sig_vectors = numpy.logical_and(sig_vectors, vec)
return sig_vectors
def evaluate_trades(self, trades):
result = {}
@ -102,4 +138,4 @@ class Solver(QObject): @@ -102,4 +138,4 @@ class Solver(QObject):
return result

28
ui/mainwindow.py

@ -10,11 +10,14 @@ from data.signal import PriceComparisonSignalGenerator, RsiSignalGenerator,\ @@ -10,11 +10,14 @@ from data.signal import PriceComparisonSignalGenerator, RsiSignalGenerator,\
AtrSignalGenerator, DayOfWeekSignalGenerator, CrtdrSignalGenerator,\
AtrDeltaSignalGenerator, SmaSignalGenerator, DayOfMonthSignalGenerator,\
CciSignalGenerator, BbandsSignalGenerator, PivotPointsSignalGenerator,\
StochasticSignalGenerator, IntradayBarNumberSignalGenerator
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):
'''
@ -28,6 +31,10 @@ class MainWindow(QMainWindow, Ui_MainWindow): @@ -28,6 +31,10 @@ class MainWindow(QMainWindow, Ui_MainWindow):
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')
@ -51,7 +58,10 @@ class MainWindow(QMainWindow, Ui_MainWindow): @@ -51,7 +58,10 @@ class MainWindow(QMainWindow, Ui_MainWindow):
self.solver.add_generator(BbandsSignalGenerator())
self.solver.add_generator(PivotPointsSignalGenerator())
self.solver.add_generator(StochasticSignalGenerator())
self.solver.add_generator(IntradayBarNumberSignalGenerator(14))
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() }
@ -68,6 +78,11 @@ class MainWindow(QMainWindow, Ui_MainWindow): @@ -68,6 +78,11 @@ class MainWindow(QMainWindow, Ui_MainWindow):
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)
@ -95,6 +110,11 @@ class MainWindow(QMainWindow, Ui_MainWindow): @@ -95,6 +110,11 @@ class MainWindow(QMainWindow, Ui_MainWindow):
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):
@ -103,6 +123,6 @@ class MainWindow(QMainWindow, Ui_MainWindow): @@ -103,6 +123,6 @@ class MainWindow(QMainWindow, Ui_MainWindow):
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)
#for trade in result['trades']:
# print(trade.entry_bar, trade.entry_price, trade.exit_price)

34
ui/mainwindow.ui

@ -211,6 +211,40 @@ @@ -211,6 +211,40 @@
</property>
</widget>
</item>
<item row="2" column="4">
<widget class="QCheckBox" name="cb_takeProfit">
<property name="text">
<string>Take profit</string>
</property>
</widget>
</item>
<item row="2" column="5">
<widget class="QDoubleSpinBox" name="sb_takeProfit">
<property name="suffix">
<string> %</string>
</property>
<property name="value">
<double>1.000000000000000</double>
</property>
</widget>
</item>
<item row="3" column="4">
<widget class="QCheckBox" name="cb_stopLoss">
<property name="text">
<string>Stop loss</string>
</property>
</widget>
</item>
<item row="3" column="5">
<widget class="QDoubleSpinBox" name="sb_stopLoss">
<property name="suffix">
<string> %</string>
</property>
<property name="value">
<double>1.000000000000000</double>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menubar">

18
ui/ui_mainwindow.py

@ -84,6 +84,20 @@ class Ui_MainWindow(object): @@ -84,6 +84,20 @@ class Ui_MainWindow(object):
self.sb_maxHoldBars.setMinimum(1)
self.sb_maxHoldBars.setObjectName("sb_maxHoldBars")
self.gridLayout.addWidget(self.sb_maxHoldBars, 2, 3, 1, 1)
self.cb_takeProfit = QtWidgets.QCheckBox(self.centralwidget)
self.cb_takeProfit.setObjectName("cb_takeProfit")
self.gridLayout.addWidget(self.cb_takeProfit, 2, 4, 1, 1)
self.sb_takeProfit = QtWidgets.QDoubleSpinBox(self.centralwidget)
self.sb_takeProfit.setProperty("value", 1.0)
self.sb_takeProfit.setObjectName("sb_takeProfit")
self.gridLayout.addWidget(self.sb_takeProfit, 2, 5, 1, 1)
self.cb_stopLoss = QtWidgets.QCheckBox(self.centralwidget)
self.cb_stopLoss.setObjectName("cb_stopLoss")
self.gridLayout.addWidget(self.cb_stopLoss, 3, 4, 1, 1)
self.sb_stopLoss = QtWidgets.QDoubleSpinBox(self.centralwidget)
self.sb_stopLoss.setProperty("value", 1.0)
self.sb_stopLoss.setObjectName("sb_stopLoss")
self.gridLayout.addWidget(self.sb_stopLoss, 3, 5, 1, 1)
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 1041, 27))
@ -120,4 +134,8 @@ class Ui_MainWindow(object): @@ -120,4 +134,8 @@ class Ui_MainWindow(object):
self.cb_minWinRate.setText(_translate("MainWindow", "Min. win rate"))
self.rb_short.setText(_translate("MainWindow", "Short"))
self.label_3.setText(_translate("MainWindow", "Max hold bars"))
self.cb_takeProfit.setText(_translate("MainWindow", "Take profit"))
self.sb_takeProfit.setSuffix(_translate("MainWindow", " %"))
self.cb_stopLoss.setText(_translate("MainWindow", "Stop loss"))
self.sb_stopLoss.setSuffix(_translate("MainWindow", " %"))

Loading…
Cancel
Save