hallo together,
in the end it might not be a big issue, but i observe following behavoir with the simple simulation (sma cross strategy) posted below:
from __future__ import (absolute_import, division, print_function,
unicode_literals)
import argparse
import backtrader as bt
import backtrader.feeds as btfeeds
import pandas
class PandasData(bt.feeds.PandasData):
params = (
('datetime', "time"),
('open','open'),
('high','high'),
('low','low'),
('close','close'),
('volume','volume'),
)
class TestSmaCross(bt.Strategy):
# list of parameters which are configurable for the strategy
params = dict(
pfast=50, # period for the fast moving average
pslow=200 # period for the slow moving average
)
def log(self, txt, dt=None):
''' Logging function fot this strategy'''
dt = dt or self.data.datetime[0]
if isinstance(dt, float):
dt = bt.num2date(dt)
print('%s, %s' % (dt.isoformat(), txt))
def __init__(self):
sma1 = bt.ind.SMA(period=self.p.pfast) # fast moving average
sma2 = bt.ind.SMA(period=self.p.pslow) # slow moving average
self.crossover = bt.ind.CrossOver(sma1, sma2) # crossover signal
def next(self):
if not self.position: # not in the market
if self.crossover > 0: # if fast crosses slow to the upside
self.buy(exectype=bt.Order.Market) # enter long
self.log('open %d, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f' %
(len(self),
self.data.open[0], self.data.high[0],
self.data.low[0], self.data.close[0],
self.data.volume[0], self.broker.getvalue()))
elif self.crossover < 0: # in the market & cross to the downside
self.close() # close long position
self.log('close %d, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f' %
(len(self),
self.data.open[0], self.data.high[0],
self.data.low[0], self.data.close[0],
self.data.volume[0], self.broker.getvalue()))
def runstrat():
args = parse_args()
# Create a cerebro entity
cerebro = bt.Cerebro()
cerebro.addstrategy(TestSmaCross)
cerebro.broker.setcash(10000.0)
cerebro.broker.setcommission(0.02)
print('Starting Portfolio Value: %.2f' % cerebro.broker.getvalue())
# Get a pandas dataframe
datapath = ('./ohlc/BTCUSDT_240.csv')
# Simulate the header row isn't there if noheaders requested
skiprows = 1 if args.noheaders else 0
header = None if args.noheaders else 0
dataframe = pandas.read_csv(datapath,
skiprows=skiprows,
header=header,
parse_dates=True,
index_col=0)
dataframe['time'] = pandas.to_datetime(dataframe['time'] * 1000, unit='ms')
if not args.noprint:
print('--------------------------------------------------')
print(dataframe)
print('--------------------------------------------------')
# Pass it to the backtrader datafeed and add it to the cerebro
data = PandasData(dataname=dataframe)
cerebro.adddata(data)
# Run over everything
cerebro.run()
print('Final Portfolio Value: %.2f' % cerebro.broker.getvalue())
# Plot the result
cerebro.plot(
# Format string for the display of ticks on the x axis
fmt_x_ticks = '%Y-%b-%d %H:%M',
# Format string for the display of data points values
fmt_x_data = '%Y-%b-%d %H:%M',
style='candlestick',
iplot=True
)
def parse_args():
parser = argparse.ArgumentParser(
description='Pandas test script')
parser.add_argument('--noheaders', action='store_true', default=False,
required=False,
help='Do not use header rows')
parser.add_argument('--noprint', action='store_true', default=False,
help='Print the dataframe')
return parser.parse_args()
if __name__ == '__main__':
runstrat()
everything works fine in the first place. positions got opened when crossover > 0, positions get closed again when crossover < 0. see the output below:
2018-02-20T16:00:00, open 214, 11517.00, 11748.01, 11494.29, 11668.00, 7241.34, 10000.00
2018-04-18T04:00:00, open 553, 7947.74, 8149.89, 7868.00, 8107.23, 5703.82, 10000.00
2018-05-15T16:00:00, close 718, 8513.08, 8588.64, 8427.00, 8554.99, 5920.56, 10279.21
2018-07-10T04:00:00, open 1048, 6632.14, 6655.46, 6544.04, 6601.17, 4874.00, 10108.12
2018-07-16T04:00:00, close 1084, 6357.75, 6389.67, 6343.61, 6370.00, 3449.90, 9744.93
2018-07-18T00:00:00, open 1095, 7317.44, 7550.00, 7309.64, 7457.03, 9867.37, 9618.31
2018-08-08T16:00:00, close 1225, 6473.78, 6490.95, 6123.00, 6335.00, 17490.34, 8345.13
2018-08-31T16:00:00, open 1363, 6959.52, 7089.00, 6951.37, 7047.48, 8537.22, 8216.65
2018-09-11T20:00:00, close 1430, 6269.23, 6323.41, 6242.09, 6294.91, 5090.82, 7324.96
2018-10-05T00:00:00, open 1569, 6591.69, 6632.98, 6543.08, 6579.00, 2300.30, 7197.19
2018-10-13T20:00:00, close 1622, 6326.21, 6338.07, 6314.23, 6332.93, 642.23, 6819.58
2018-10-19T20:00:00, open 1658, 6555.38, 6560.00, 6523.00, 6528.88, 3836.21, 6692.92
2018-10-28T08:00:00, close 1709, 6492.98, 6497.94, 6482.33, 6493.22, 748.54, 6526.68
2018-12-25T08:00:00, open 2056, 3750.57, 3786.95, 3684.00, 3737.31, 9248.18, 6396.81
2019-01-15T20:00:00, close 2185, 3604.14, 3605.00, 3516.62, 3553.06, 8567.48, 6139.30
2019-02-12T20:00:00, open 2353, 3640.18, 3654.94, 3609.00, 3631.46, 4169.11, 6068.24
2019-06-11T16:00:00, close 3063, 7761.92, 7900.98, 7692.23, 7868.87, 5502.25, 10232.97
2019-06-15T20:00:00, open 3088, 8809.28, 8842.48, 8725.17, 8808.70, 3618.34, 10075.41
2019-07-18T12:00:00, close 3284, 9751.31, 10455.00, 9252.00, 10437.93, 31624.51, 11526.36
2019-08-07T04:00:00, open 3402, 11640.01, 11725.27, 11525.96, 11538.61, 6684.94, 11322.61
2019-09-10T16:00:00, open 3608, 10176.26, 10238.26, 9953.00, 10026.31, 7691.44, 11322.61
2019-09-22T00:00:00, close 3676, 9985.15, 10004.33, 9861.55, 9873.17, 3997.09, 10969.66
2019-10-27T16:00:00, open 3890, 9523.98, 9794.98, 9376.00, 9712.73, 19848.68, 10771.81
2019-11-17T12:00:00, close 4015, 8521.26, 8574.37, 8511.26, 8529.99, 4195.95, 9395.56
2019-12-29T00:00:00, open 4264, 7315.36, 7316.14, 7288.00, 7307.27, 2401.81, 9224.50
2020-01-01T04:00:00, close 4283, 7225.00, 7236.27, 7199.11, 7209.83, 2061.30, 8981.13
2020-01-02T00:00:00, open 4288, 7200.77, 7212.50, 7120.37, 7129.61, 3739.35, 8836.93
2020-01-02T20:00:00, close 4293, 6982.63, 6985.00, 6941.27, 6965.71, 3113.89, 8530.80
2020-01-03T08:00:00, open 4296, 7202.28, 7371.92, 7202.28, 7340.46, 15196.89, 8391.27
2020-02-27T08:00:00, close 4625, 8814.21, 8859.42, 8730.00, 8804.36, 9960.10, 9708.37
2020-04-07T04:00:00, open 4864, 7322.08, 7388.00, 7226.07, 7378.08, 14375.84, 9532.19
2020-06-18T12:00:00, close 5298, 9432.67, 9445.00, 9381.00, 9385.99, 7578.09, 11393.37
2020-07-23T20:00:00, open 5510, 9595.67, 9610.00, 9567.24, 9603.27, 3971.70, 11205.65
2020-08-29T08:00:00, close 5729, 11558.28, 11569.72, 11417.04, 11447.38, 6311.20, 12857.70
2020-10-02T08:00:00, open 5933, 10490.88, 10495.00, 10374.00, 10436.63, 10230.65, 12628.75
2021-01-27T08:00:00, close 6635, 31743.33, 31749.28, 30578.94, 30639.05, 16124.25, 32622.44
2021-02-05T16:00:00, open 6691, 37960.76, 38163.34, 37230.00, 37608.92, 12503.52, 32006.41
2021-05-08T16:00:00, open 7243, 57599.86, 59300.00, 57560.63, 59030.56, 13538.22, 32006.41
2021-06-18T04:00:00, open 7486, 37926.78, 38148.11, 37377.00, 37715.03, 10812.08, 32006.41
2021-07-27T16:00:00, open 7723, 38209.58, 38315.81, 37350.00, 37800.49, 13516.23, 32006.41
2021-10-06T08:00:00, open 8147, 51450.00, 51500.00, 50382.41, 51306.56, 14543.36, 32006.41
2022-02-08T16:00:00, open 8899, 43429.32, 43685.20, 42666.00, 42998.65, 9095.17, 32006.41
2022-03-04T16:00:00, open 9043, 40694.32, 40958.66, 39665.72, 39782.13, 10513.62, 32006.41
2022-03-08T08:00:00, open 9065, 38547.79, 39186.58, 38460.28, 38983.05, 8572.44, 32006.41
2022-03-20T08:00:00, open 9137, 41863.99, 41937.99, 41575.00, 41586.86, 4753.40, 32006.41
2022-06-10T00:00:00, open 9627, 30109.93, 30382.80, 29578.96, 30114.38, 15509.84, 32006.41
2022-06-12T08:00:00, close 9641, 27645.88, 27726.15, 27342.82, 27457.39, 8692.74, 28747.14
at some point, positions won't get closed anymore, starting at 2021-02-05T16:00:00 on the output log above. it seems like following condition is not reached anymore:
elif self.crossover < 0: # in the market & cross to the downside
self.close() # close long position
self.log('close %d, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f' %
(len(self),
self.data.open[0], self.data.high[0],
self.data.low[0], self.data.close[0],
self.data.volume[0], self.broker.getvalue()))
the plot on the other hand shows all crossover events correctly:
Figure_0.png
until now i didn't figure out, what i'm doing wrong; because it is even working fine in the first place.
thanks for your help in advance.
regards, alex