9 changed files with 518 additions and 92 deletions
@ -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 += """ |
||||
} |
||||
} |
||||
} |
||||
""" |
||||
|
||||
|
||||
|
||||
@ -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 |
||||
|
||||
|
||||
Loading…
Reference in new issue