from __future__ import (absolute_import, division, print_function, | |
unicode_literals) | |
import argparse | |
import datetime # For datetime objects | |
import os.path # To manage paths | |
import sys # To find out the script name (in argv[0]) | |
import math | |
# Import the backtrader platform | |
import backtrader as bt | |
from backtrader.utils import flushfile # win32 quick stdout flushing | |
import pandas as pd | |
import numpy as np | |
class SimpleMLPPredictor(bt.Indicator): | |
lines = ('predict',) | |
params = (('period', 10),) | |
def __init__(self): | |
self.addminperiod(self.params.period) | |
def next(self): | |
self.lines.predict[0] = get_prediction(np.random.choice([0,1])) | |
# Create Custom position sizer | |
class FixedReverser(bt.Sizer): | |
params = (('stake', 1),) | |
def _getsizing(self, comminfo, cash, data, isbuy): | |
position = self.broker.getposition(data) | |
size = self.p.stake * (1 + (position.size != 0)) | |
return size | |
################################################# | |
class LongShortStrategyESDaily(bt.Strategy): | |
params = dict( | |
smaperiod=10, | |
trade=False, | |
#stake=1, | |
exectype=bt.Order.Market, | |
stopafter=0, | |
valid=None, | |
cancel=0, | |
donotsell=False, | |
) | |
def log(self, txt, dt=None): | |
''' Logging function fot this strategy''' | |
dt = dt or self.datas[0].datetime.datetime(0) | |
print('%s, %s' % (dt.isoformat(), txt)) | |
def __init__(self): | |
# Keep a reference to the "close" line in the data[0] dataseries | |
self.dataclose = self.datas[0].close | |
self.dataopen = self.datas[0].open | |
# To control operation entries | |
self.orderid = list() | |
self.order = None | |
self.counttostop = 0 | |
self.datastatus = 0 | |
# Create SMA on 2nd data | |
self.predict = SimpleMLPPredictor() | |
print('--------------------------------------------------') | |
print('Strategy Created') | |
print('--------------------------------------------------') | |
def notify_data(self, data, status, *args, **kwargs): | |
print('*' * 5, datetime.datetime.now(), 'DATA NOTIF:', data._getstatusname(status), *args) | |
if status == data.LIVE: | |
self.counttostop = self.p.stopafter | |
self.datastatus = 1 | |
def notify_store(self, msg, *args, **kwargs): | |
print('*' * 5, datetime.datetime.now(), 'STORE NOTIF:', msg) | |
def notify_order(self, order): | |
if order.status in [order.Completed, order.Cancelled, order.Rejected]: | |
self.order = None | |
print('-' * 50, datetime.datetime.now(), 'ORDER BEGIN') | |
print(order) | |
print('-' * 50, datetime.datetime.now(), 'ORDER END') | |
def notify_trade(self, trade): | |
print('-' * 50, datetime.datetime.now(), 'TRADE BEGIN') | |
print(trade) | |
print('-' * 50, datetime.datetime.now(), 'TRADE END') | |
def prenext(self): | |
self.next(frompre=True) | |
def next(self, frompre=False): | |
txt = list() | |
txt.append('%04d' % len(self)) | |
dtfmt = '%Y-%m-%dT%H:%M:%S.%f' | |
txt.append('%s' % self.data.datetime.datetime(0).strftime(dtfmt)) | |
txt.append('{}'.format(self.data.open[0])) | |
txt.append('{}'.format(self.data.high[0])) | |
txt.append('{}'.format(self.data.low[0])) | |
txt.append('{}'.format(self.data.close[0])) | |
txt.append('{}'.format(self.data.volume[0])) | |
txt.append('{}'.format(self.position.size)) | |
txt.append('{}'.format(self.predict[0])) | |
print(', '.join(txt)) | |
if self.counttostop: # stop after x live lines | |
self.counttostop -= 1 | |
if not self.counttostop: | |
self.env.runstop() | |
return | |
if not self.p.trade: | |
return | |
if self.datastatus and not self.position and len(self.orderid) < 1: | |
if self.predict[0] == 1: | |
# BUY, BUY, BUY!!! (with all possible default parameters) | |
self.log('GO LONG, %.2f' % self.data.close[0]) | |
# Keep track of the created order to avoid a 2nd order | |
self.order = self.buy() | |
elif self.predict[0] == 0: | |
# SELL, SELL, SELL!!! (with all possible default parameters) | |
self.log('GO SHORT, %.2f' % self.data.close[0]) | |
# Keep track of the created order to avoid a 2nd order | |
self.order = self.sell() | |
self.orderid.append(self.order) | |
elif self.datastatus and self.position.size > 0: | |
if self.predict[0] == 1: | |
pass | |
# BUY, BUY, BUY!!! (with all possible default parameters) | |
#self.log('GO LONG, %.2f' % self.dataclose[0]) | |
# Keep track of the created order to avoid a 2nd order | |
#self.order = self.buy() | |
elif self.predict[0] == 0: | |
# SELL, SELL, SELL!!! (with all possible default parameters) | |
self.log('REVERSE LONG TO SHORT, %.2f' % self.data.close[0]) | |
# Keep track of the created order to avoid a 2nd order | |
self.order = self.sell() | |
self.orderid.append(self.order) | |
elif self.datastatus and self.position.size < 0: | |
if self.predict[0] == 1: | |
# BUY, BUY, BUY!!! (with all possible default parameters) | |
self.log('REVERSE SHORT TO LONG, %.2f' % self.data.close[0]) | |
# Keep track of the created order to avoid a 2nd order | |
self.order = self.buy() | |
elif self.predict[0] == 0: | |
pass | |
# SELL, SELL, SELL!!! (with all possible default parameters) | |
#self.log('GO SHORT, %.2f' % self.dataclose[0]) | |
# Keep track of the created order to avoid a 2nd order | |
#self.order = self.sell() | |
elif self.order is not None and self.p.cancel: | |
if self.datastatus > self.p.cancel: | |
self.cancel(self.order) | |
if self.datastatus: | |
self.datastatus += 1 | |
def start(self): | |
if self.data0.contractdetails is not None: | |
print('Timezone from ContractDetails: {}'.format( | |
self.data0.contractdetails.m_timeZoneId)) | |
header = ['Datetime', 'Open', 'High', 'Low', 'Close', 'Volume', | |
'OpenPositionSize', 'Forecast'] | |
print(', '.join(header)) | |
self.done = False | |
def runstrategy(): | |
# Create a cerebro | |
cerebro = bt.Cerebro() | |
storekwargs = dict( | |
host='127.0.0.1', port=4003, | |
clientId=103, | |
timeoffset=not None, | |
reconnect=3, | |
timeout=3.0, | |
notifyall=None, | |
_debug=None | |
) | |
ibstore = bt.stores.IBStore(**storekwargs) | |
broker = ibstore.getbroker() | |
cerebro.setbroker(broker) | |
timeframe = bt.TimeFrame.Days | |
datatf = datatf1 = bt.TimeFrame.Ticks | |
datacomp = datacomp1 = 1 | |
IBDataFactory = ibstore.getdata | |
datakwargs = dict( | |
timeframe=datatf, | |
compression=datacomp, | |
historical=None, | |
#fromdate=None, | |
fromdate=datetime.datetime(2016, 12, 1), | |
#todate=datetime.datetime(2016, 12, 3), | |
rtbar=None, | |
qcheck=0.5, | |
what=None, | |
backfill_start=not None, | |
backfill=not None, | |
latethrough=None, | |
tz=None | |
) | |
data0 = IBDataFactory(dataname='ES-201703-GLOBEX', **datakwargs) | |
rekwargs = dict( | |
timeframe=timeframe, | |
compression=datacomp, | |
bar2edge=not None, | |
adjbartime=not None, | |
rightedge=not None, | |
takelate=not None, | |
) | |
cerebro.resampledata(dataname=data0, **rekwargs) | |
cerebro.addstrategy(LongShortStrategyESDaily, | |
smaperiod=10, | |
trade=True, | |
exectype=bt.bt.Order.Market, | |
#stake=1, | |
stopafter=None, | |
valid=None, | |
cancel=0, | |
donotsell=None | |
) | |
cerebro.addsizer(FixedReverser) | |
# Live data ... avoid long data accumulation by switching to "exactbars" | |
cerebro.run() | |
#if args.plot and args.exactbars < 1: # plot if possible | |
cerebro.plot() | |
if __name__ == '__main__': | |
runstrategy() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment