In [ ]:
Copied!
!pip install git+https://github.com/paulknysh/blackbox.git@master
!pip install git+https://github.com/paulknysh/blackbox.git@master
Sample strategy¶
In [1]:
Copied!
import talib.abstract as ta
from lettrade import DataFeed, Strategy, indicator as i
from lettrade.exchange.backtest import ForexBackTestAccount, let_backtest
class SmaCross(Strategy):
ema1_window = 9
ema2_window = 21
def indicators(self, df: DataFeed):
df["ema1"] = ta.EMA(df, timeperiod=self.ema1_window)
df["ema2"] = ta.EMA(df, timeperiod=self.ema2_window)
df["signal_ema_crossover"] = i.crossover(df.ema1, df.ema2)
df["signal_ema_crossunder"] = i.crossunder(df.ema1, df.ema2)
def next(self, df: DataFeed):
if len(self.orders) > 0 or len(self.positions) > 0:
return
if df.l.signal_ema_crossover[-1]:
price = self.data.l.close[-1]
self.buy(size=0.1, sl=price - 0.001, tp=price + 0.001)
elif df.l.signal_ema_crossunder[-1]:
price = self.data.l.close[-1]
self.sell(size=0.1, sl=price + 0.001, tp=price - 0.001)
lt = let_backtest(
strategy=SmaCross,
datas="example/data/data/EURUSD_5m-0_10000.csv",
account=ForexBackTestAccount,
)
import talib.abstract as ta
from lettrade import DataFeed, Strategy, indicator as i
from lettrade.exchange.backtest import ForexBackTestAccount, let_backtest
class SmaCross(Strategy):
ema1_window = 9
ema2_window = 21
def indicators(self, df: DataFeed):
df["ema1"] = ta.EMA(df, timeperiod=self.ema1_window)
df["ema2"] = ta.EMA(df, timeperiod=self.ema2_window)
df["signal_ema_crossover"] = i.crossover(df.ema1, df.ema2)
df["signal_ema_crossunder"] = i.crossunder(df.ema1, df.ema2)
def next(self, df: DataFeed):
if len(self.orders) > 0 or len(self.positions) > 0:
return
if df.l.signal_ema_crossover[-1]:
price = self.data.l.close[-1]
self.buy(size=0.1, sl=price - 0.001, tp=price + 0.001)
elif df.l.signal_ema_crossunder[-1]:
price = self.data.l.close[-1]
self.sell(size=0.1, sl=price + 0.001, tp=price - 0.001)
lt = let_backtest(
strategy=SmaCross,
datas="example/data/data/EURUSD_5m-0_10000.csv",
account=ForexBackTestAccount,
)
Run optimize¶
In [2]:
Copied!
import blackbox as bb
def params_parser(args):
return {"ema1_window": int(args[0]), "ema2_window": int(args[1])}
def result_parser(result):
return result["equity"]
result = bb.minimize(
f=lt.optimize_model(
params_parser=params_parser,
result_parser=result_parser,
),
domain=[[5, 25, 1], [10, 50, 1]], # ranges of each parameter
budget=300, # total number of function calls available
batch=12, # number of calls that will be evaluated in parallel
)
lt.optimize_done()
import blackbox as bb
def params_parser(args):
return {"ema1_window": int(args[0]), "ema2_window": int(args[1])}
def result_parser(result):
return result["equity"]
result = bb.minimize(
f=lt.optimize_model(
params_parser=params_parser,
result_parser=result_parser,
),
domain=[[5, 25, 1], [10, 50, 1]], # ranges of each parameter
budget=300, # total number of function calls available
batch=12, # number of calls that will be evaluated in parallel
)
lt.optimize_done()
INFO evaluating batch 1/25 (samples 1..12/300) 07-02 16:52:35 INFO evaluating batch 2/25 (samples 13..24/300) 07-02 16:52:36 INFO evaluating batch 3/25 (samples 25..36/300) 07-02 16:52:36 INFO evaluating batch 4/25 (samples 37..48/300) 07-02 16:52:37 INFO evaluating batch 5/25 (samples 49..60/300) 07-02 16:52:37 INFO evaluating batch 6/25 (samples 61..72/300) 07-02 16:52:37 INFO evaluating batch 7/25 (samples 73..84/300) 07-02 16:52:38 INFO evaluating batch 8/25 (samples 85..96/300) 07-02 16:52:38 INFO evaluating batch 9/25 (samples 97..108/300) 07-02 16:52:39 INFO evaluating batch 10/25 (samples 109..120/300) 07-02 16:52:39 INFO evaluating batch 11/25 (samples 121..132/300) 07-02 16:52:40 INFO evaluating batch 12/25 (samples 133..144/300) 07-02 16:52:40 INFO evaluating batch 13/25 (samples 145..156/300) 07-02 16:52:41 INFO evaluating batch 14/25 (samples 157..168/300) 07-02 16:52:41 INFO evaluating batch 15/25 (samples 169..180/300) 07-02 16:52:44 INFO evaluating batch 16/25 (samples 181..192/300) 07-02 16:52:46 INFO evaluating batch 17/25 (samples 193..204/300) 07-02 16:52:48 INFO evaluating batch 18/25 (samples 205..216/300) 07-02 16:52:50 INFO evaluating batch 19/25 (samples 217..228/300) 07-02 16:52:52 INFO evaluating batch 20/25 (samples 229..240/300) 07-02 16:52:54 INFO evaluating batch 21/25 (samples 241..252/300) 07-02 16:52:57 INFO evaluating batch 22/25 (samples 253..264/300) 07-02 16:53:00 INFO evaluating batch 23/25 (samples 265..276/300) 07-02 16:53:03 INFO evaluating batch 24/25 (samples 277..288/300) 07-02 16:53:06 INFO evaluating batch 25/25 (samples 289..300/300) 07-02 16:53:09 INFO DONE 07-02 16:53:13
Plot¶
In [3]:
Copied!
lt.plotter.heatmap(x="ema1_window", y="ema2_window")
lt.plotter.heatmap(x="ema1_window", y="ema2_window")
In [4]:
Copied!
lt.plotter.contour(x="ema1_window", y="ema2_window")
lt.plotter.contour(x="ema1_window", y="ema2_window")
In [5]:
Copied!
import plotly.io as pio
pio.renderers.default = "notebook"
pio.templates.default = "plotly_dark"
import plotly.io as pio
pio.renderers.default = "notebook"
pio.templates.default = "plotly_dark"
Clean data¶
In [6]:
Copied!
import pandas as pd
df = pd.DataFrame(
{
"ema1_window": [r[0] for r in result["all_xs"]],
"ema2_window": [r[1] for r in result["all_xs"]],
"equity": result["all_fs"],
}
)
df.columns = ["x", "y", "z"]
df.x = df.x.astype(int)
df.y = df.y.astype(int)
df
import pandas as pd
df = pd.DataFrame(
{
"ema1_window": [r[0] for r in result["all_xs"]],
"ema2_window": [r[1] for r in result["all_xs"]],
"equity": result["all_fs"],
}
)
df.columns = ["x", "y", "z"]
df.x = df.x.astype(int)
df.y = df.y.astype(int)
df
Out[6]:
x | y | z | |
---|---|---|---|
0 | 10 | 12 | 9833.68 |
1 | 5 | 35 | 9874.68 |
2 | 20 | 18 | 10074.90 |
3 | 15 | 41 | 9981.80 |
4 | 10 | 23 | 9857.78 |
... | ... | ... | ... |
295 | 10 | 28 | 9845.10 |
296 | 21 | 34 | 9890.22 |
297 | 6 | 39 | 9905.94 |
298 | 10 | 14 | 9809.16 |
299 | 16 | 32 | 9927.24 |
300 rows × 3 columns
Type 1¶
In [7]:
Copied!
import plotly.express as px
fig = px.density_contour(
df,
x="x",
y="y",
z="z",
histfunc="max",
)
fig.update_traces(contours_coloring="fill", contours_showlabels=True)
fig.show()
import plotly.express as px
fig = px.density_contour(
df,
x="x",
y="y",
z="z",
histfunc="max",
)
fig.update_traces(contours_coloring="fill", contours_showlabels=True)
fig.show()
Type 2¶
In [8]:
Copied!
import plotly.express as px
fig = px.density_heatmap(
df,
x="x",
y="y",
z="z",
nbinsx=20,
nbinsy=40,
histfunc="max",
color_continuous_scale="Viridis",
)
fig.show()
import plotly.express as px
fig = px.density_heatmap(
df,
x="x",
y="y",
z="z",
nbinsx=20,
nbinsy=40,
histfunc="max",
color_continuous_scale="Viridis",
)
fig.show()
Type 3¶
In [9]:
Copied!
import plotly.graph_objects as go
fig = go.Figure(
go.Histogram2d(
x=df.x,
y=df.y,
z=df.z,
nbinsx=20,
nbinsy=40,
histfunc="max",
)
)
fig.show()
import plotly.graph_objects as go
fig = go.Figure(
go.Histogram2d(
x=df.x,
y=df.y,
z=df.z,
nbinsx=20,
nbinsy=40,
histfunc="max",
)
)
fig.show()
Source¶
--8<-- "example/optimize/blackbox.py"