You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

111 lines
3.1 KiB

import datetime
import pandas as pd
import backtrader as bt
import strategies as st
COLUMNS = [
"froi%",
"cost",
"total_value",
"#deals",
"#units",
"comms",
"monthly",
"annual%",
"max_dd_days",
"max_dd%",
"max_md",
"vwr",
]
# import data
def get_data(
stocks,
start=datetime.datetime.fromisoformat("1928-01-01"),
end=datetime.datetime.now(),
):
from pandas_datareader.yahoo.daily import YahooDailyReader
import requests_cache
expire_after = datetime.timedelta(days=1)
session = requests_cache.CachedSession(
cache_name="cache", backend="sqlite", expire_after=expire_after
)
reader = YahooDailyReader(
stocks,
datetime.datetime.fromisoformat("1900-01-01"),
datetime.datetime.now(),
session=session,
)
session.headers = reader.headers
return reader.read().loc[start:end]
def get_data_borders(stockData):
actual_start: datetime.datetime = stockData.index[0]
actual_end: datetime.datetime = stockData.index[-1]
return actual_start, actual_end
def human_readable_size(size, decimal_places=3):
for unit in ["$", "K$", "M$", "G$", "T$", "P$"]:
if size < 1000.0 or unit == "P$":
return f"{size:.{decimal_places}f}{unit}"
break
size /= 1000.0
def prepare_simulation(strategy, params, data, fund_mode=False):
if fund_mode:
cerebro = bt.Cerebro()
cerebro.addobserver(bt.observers.FundShares)
else:
cerebro = bt.Cerebro(stdstats=False)
cerebro.addobserver(bt.observers.Broker)
cerebro.addobserver(bt.observers.BuySell)
cerebro.adddata(data)
cerebro.addstrategy(strategy, params)
# Broker Information
broker_args = dict(coc=True, cash=params["sum"])
cerebro.broker = bt.brokers.BackBroker(**broker_args)
comminfo = st.PercentageCommisionScheme()
cerebro.broker.addcommissioninfo(comminfo)
if fund_mode:
cerebro.broker.set_fundmode(True)
cerebro.addanalyzer(bt.analyzers.DrawDown, _name="drawdown")
cerebro.addanalyzer(bt.analyzers.VWR, _name="returns")
return cerebro
def test_strategy(stockData, strategy, monthly_params):
pd.options.display.float_format = "{:,.2f}".format
df = pd.DataFrame(columns=COLUMNS)
actual_start, actual_end = get_data_borders(stockData)
data = bt.feeds.PandasData(dataname=stockData)
cerebro = prepare_simulation(strategy, monthly_params, data)
therun = cerebro.run()[0]
# cerebro.plot(iplot=False, style="candlestick")
dd = therun.analyzers.drawdown
ret = therun.analyzers.returns
params = therun.calc_params()
# omg IM so sorry for this, ironically this is here to get human readable size
for i in 1, 2, 5, 6:
params[i] = human_readable_size(params[i])
annual = 100 * (
(1 + params[0] / 100) ** (365 / (actual_end - actual_start).days) - 1
)
df.loc[strategy.__name__] = params + [
annual,
dd.get_analysis().max.len,
dd.get_analysis().max.drawdown,
human_readable_size(dd.get_analysis().max.moneydown),
ret.get_analysis()["vwr"],
]
return df