ah, i shouldve put the results, sorry. I already found the fix :D
Best posts made by Edward Owen
-
RE: Using Donchian Channel to execute buy order
-
RE: Sizer problem
@ab_trader said in Sizer problem:
@Edward-Owen said in Sizer problem:
Some of the costs are negative.
cost = size x price
size
is negative for short position, therforecost
is also negative.I am quite new to python and backtrader, can you point me out which code is shorting my trades, I thought that my code only goes long.
Latest posts made by Edward Owen
-
RE: Running a backtest from a single class
i got it!
I insert few functions to call the values from bt.cerebro to mimic cerebro.broker.getcash()
but any other solutions are welcome!
-
Running a backtest from a single class
Hi,
I am doing a web project using Backtrader for my class. Basically, the web page allows users to input variables such as initial cash, indicator values, risk management values, etc, and run a simple backtest with Backtrader from the web itself.
As far as I know, to run a simple strategy you'll need to
- Instantiate Cerebro
- cerebro.broker.addstrategy(strategy)
- Add Data and set cash
- cerebro.run()
To backtest from the web I have to run the backtest from a single class. I named the class "Simulate" and have decided to insert steps 1-4 into the class' __ init __
class Simulate: def __init__(self, initialCash): self.cash = initialCash self.cerebro = bt.Cerebro() #self.TestStrategy = TestStrategy() self.cerebro.addstrategy(TestStrategy) data = bt.feeds.YahooFinanceCSVData( dataname="datas/Misc/orcl-1995-2014.txt", fromdate=datetime.datetime(2000, 1, 1), todate=datetime.datetime(2000, 12, 31), reverse=False) self.cerebro.adddata(data) self.cerebro.broker.setcash(self.cash) print('Starting Portfolio Value: %.2f' % self.cerebro.broker.getvalue()) self.cerebro.run() print('Final Portfolio Value: %.2f' % self.cerebro.broker.getvalue()) self.cerebro.plot(style="candlestick", barup='green', bardown='red')
The bt.strategy class that I will be using is outside of the "Simulate" class.
class Simulate: ... class TestStrategy(bt.Strategy): ...
Let's say in this example I wanted to log the "Initial Cash" every time I place a Buy order. This "Initial Cash" is supposed to be in Simulate's __ init __
class Simulate: def __init__(self, initialCash): self.cash = initialCash
and to log
- Buy Create's Close
- Current Cash
- Initial Cash
self.log('BUY CREATE, %.2f, Cash: %.2f, Initial Cash:%.2f' % ( self.dataclose[0],self.cerebro.broker.getcash(), self.cash))
How do I get the values from Simulate class to the strategy class, I've been trying to solve this for days, but just can't figure it out. Please help :c
.
.
.
Here is the full code(the strategy is an example strategy from the quickstart docs):from __future__ import (absolute_import, division, print_function, unicode_literals) import backtrader as bt import datetime class Simulate: def __init__(self, initialCash): self.cash = initialCash self.cerebro = bt.Cerebro() #self.TestStrategy = TestStrategy() self.cerebro.addstrategy(TestStrategy) data = bt.feeds.YahooFinanceCSVData( dataname="datas/Misc/orcl-1995-2014.txt", fromdate=datetime.datetime(2000, 1, 1), todate=datetime.datetime(2000, 12, 31), reverse=False) self.cerebro.adddata(data) self.cerebro.broker.setcash(self.cash) print('Starting Portfolio Value: %.2f' % self.cerebro.broker.getvalue()) self.cerebro.run() print('Final Portfolio Value: %.2f' % self.cerebro.broker.getvalue()) self.cerebro.plot(style="candlestick", barup='green', bardown='red') class TestStrategy(bt.Strategy): def log(self, txt, dt=None): dt = dt or self.datas[0].datetime.date(0) print('%s, %s' % (dt.isoformat(), txt)) def __init__(self): self.dataclose = self.datas[0].close def notify_order(self, order): if order.status in [order.Submitted, order.Accepted]: return if order.status in [order.Completed]: if order.isbuy(): self.log('BUY EXECUTED, %.2f' % order.executed.price) elif order.issell(): self.log('SELL EXECUTED, %.2f' % order.executed.price) self.bar_executed = len(self) elif order.status in [order.Canceled, order.Margin, order.Rejected]: self.log('Order Canceled/Margin/Rejected') self.order = None def next(self): self.log('Close, %.2f' % self.dataclose[0]) if self.dataclose[0] < self.dataclose[-1]: if self.dataclose[-1] < self.dataclose[-2]: self.log('BUY CREATE, %.2f, Cash: %.2f, Initial Cash:%.2f' % ( self.dataclose[0],self.cerebro.broker.getcash(), self.cash)) self.buy() Simulate(100000)
-
RE: Sizer problem
@ab_trader said in Sizer problem:
@Edward-Owen said in Sizer problem:
Some of the costs are negative.
cost = size x price
size
is negative for short position, therforecost
is also negative.I am quite new to python and backtrader, can you point me out which code is shorting my trades, I thought that my code only goes long.
-
Sizer problem
So I tried using an example sizer from Backtest-Rookies and implemented it to my own code
https://backtest-rookies.com/2017/07/24/developing-sizers-backtrader-part-1/
#This is the example code that they provided:
class MaxRiskSizer(bt.Sizer): ''' Returns the number of shares rounded down that can be purchased for the max rish tolerance ''' params = (('risk', 0.03),) def __init__(self): if self.p.risk > 1 or self.p.risk < 0: raise ValueError('The risk parameter is a percentage which must be' 'entered as a float. e.g. 0.5') def _getsizing(self, comminfo, cash, data, isbuy): if isbuy: size = math.floor((cash * self.p.risk) / data[0]) else: size = math.floor((cash * self.p.risk) / data[0]) * -1 return size cerebro.addsizer(MaxRiskSizer, risk=0.5)
...............................................................................................................................................................
I set the risk at (risk = 0.5) , so it should mean I am going to use 50% of the portfolio to enter a trade right?#This is my code(I seperated the stategy class and main):
- Main:
import backtrader as bt import datetime import math from Strategy import TestStrategy cerebro = bt.Cerebro() cerebro.broker.set_cash(100000) cerebro.broker.setcommission(0.01) data = bt.feeds.YahooFinanceCSVData( dataname="oracle.csv", fromdate=datetime.datetime(2000,3,1), todate=datetime.datetime(2000,4,29), reverse=False) class MaxRiskSizer(bt.Sizer): ''' Returns the number of shares rounded down that can be purchased for the max rish tolerance ''' params = (('risk', 0.03),) def __init__(self): if self.p.risk > 1 or self.p.risk < 0: raise ValueError('The risk parameter is a percentage which must be' 'entered as a float. e.g. 0.5') def _getsizing(self, comminfo, cash, data, isbuy): if isbuy: size = math.floor((cash * self.p.risk) / data[0]) else: size = math.floor((cash * self.p.risk) / data[0]) * -1 return size cerebro.adddata(data) #Insert Data. cerebro.addstrategy(TestStrategy) #cerebro.addsizer(bt.sizers.FixedSize, stake=2) cerebro.addsizer(MaxRiskSizer, risk=0.5) print("Starting Portfolio :%.2f" % cerebro.broker.getvalue()) print() cerebro.run() print("Final Portfolio Value:%.2f" % cerebro.broker.getvalue()) cerebro.plot(style="candlestick",barup='green', bardown='red')
- Strategy class :
import backtrader as bt class TestStrategy(bt.Strategy): def log(self, txt, dt=None): ''' Logging function for this strategy''' dt = dt or self.datas[0].datetime.date(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 # To keep track of pending orders and buy price/commission self.order = None self.buyprice = None self.buycomm = None def notify_order(self,order): if order.status in [order.Submitted, order.Accepted]: return # Check if an order has been completed. Broker could reject if not enough cash if order.status in[order.Completed]: if order.isbuy(): self.log("BUY EXECUTED,Price: %.2f, Cost: %.2f, Comm %.2f" % (order.executed.price, order.executed.value, order.executed.comm)) self.buyprice = order.executed.price self.buycomm = order.executed.comm elif order.issell(): self.log("SELL EXECUTED,Price: %.2f, Cost: %.2f, Comm %.2f" % (order.executed.price, order.executed.value, order.executed.comm)) self.bar_executed = len(self) elif order.status in [order.Canceled, order.Margin, order.Rejected]: self.log("Order Cancled/Margin/Rejected") self.order = None def notify_trade(self, trade): if not trade.isclosed: return self.log("OPERATION PROFIT, GROSS %.2f NET %.2f" % (trade.pnl, trade.pnlcomm)) print() def next(self): # Simply log the closing price of the series from the reference #self.log('Close, %.2f' % self.dataclose[0]) if self.order: return #If we are not in the market, we might buy. if not self.position: if self.dataclose[0] < self.dataclose[-1]: # current close less than previous close if self.dataclose[-1] < self.dataclose[-2]: # previous close less than the previous previous close # BUY, BUY, BUY!!! (with all possible default parameters) self.log('BUY CREATED, %.2f' % self.dataclose[0]) self.order = self.buy() else: if len(self) >= (self.bar_executed + 5): self.log("SELL CREATED {}".format(self.dataclose[0])) self.order = self.sell()
...............................................................................................................................................................
Starting Portfolio :100000.002000-03-02, BUY CREATED, 30.47
2000-03-03, BUY EXECUTED,Price: 31.63, Cost: 51873.20, Comm 518.73
2000-03-10, SELL CREATED 36.3
2000-03-13, SELL EXECUTED,Price: 34.91, Cost: 20717.65, Comm 228.66
2000-03-20, SELL CREATED 34.75
2000-03-21, SELL EXECUTED,Price: 34.63, Cost: 30289.80, Comm 349.76
2000-03-21, OPERATION PROFIT, GROSS 5103.40 NET 4014.902000-03-28, SELL CREATED 38.5
2000-03-29, SELL EXECUTED,Price: 38.28, Cost: -52099.08, Comm 520.99
2000-04-05, SELL CREATED 34.8
2000-04-06, SELL EXECUTED,Price: 35.86, Cost: -80577.42, Comm 805.77
2000-04-13, SELL CREATED 31.99
2000-04-14, SELL EXECUTED,Price: 31.10, Cost: -114821.20, Comm 1148.21
2000-04-24, SELL CREATED 32.22
2000-04-25, SELL EXECUTED,Price: 33.30, Cost: -180785.70, Comm 1807.86
Final Portfolio Value:75467.86
...............................................................................................................................................................Problem is:
-
Just on the first buy, my portfolio starts at $100k but it uses $51.8k instead of amount < $50k. (Note: risk is 0.5)
-
Some of the costs are negative. :/
so,
how do I fix the negative, is there something I am missing out or don't understand? -
RE: Using Donchian Channel to execute buy order
ah, i shouldve put the results, sorry. I already found the fix :D
-
Using Donchian Channel to execute buy order
hi,
I am new to backtrader and even python. I know I shouldn't be rushing but I just wanna get this to work. I have only watched a few tutorials on backtrading but not much.
So I am planning to use the provided
https://www.backtrader.com/recipes/indicators/donchian/donchian/
and use it to execute a buy order on DC 5 day.Here is the code
import backtrader as bt
import datetimecerebro = bt.Cerebro()
cerebro.broker.set_cash(1000000)
data = bt.feeds.YahooFinanceCSVData(
dataname="oracle.csv",
fromdate=datetime.datetime(2000,1,1),
todate=datetime.datetime(2000,12,31),
reverse=False)cerebro.adddata(data) #Insert Data.
class DonchianChannels(bt.Strategy):
#DONCHIAN CHANNELS PLOTTING
alias = ('DCH', 'DonchianChannel',)
lines = ( 'dch', 'dcl',) # dc middle, dc high, dc low
params = dict(
period=5,
lookback=-1, #look at Params Note.
)
plotinfo = dict(subplot=False) # plot along with data
plotlines = dict(
dch=dict(_samecolor=True), # use same color as prev line (dcm)
dcl=dict(_samecolor=True), # use same color as prev line (dch)
)def __init__(self): self.dataclose = self.datas[0].close self.order = None #DC hi, lo = self.data.high, self.data.low if self.p.lookback: # move backwards as needed hi, lo = hi(self.p.lookback), lo(self.p.lookback) self.l.dch = bt.ind.Highest(hi, period=self.p.period) self.l.dcl = bt.ind.Lowest(lo, period=self.p.period) self.l.dcm = (self.l.dch + self.l.dcl) / 2.0 # avg of the above def next(self): # Simply log the closing price of the series from the reference self.log('Close, %.2f' % self.dataclose[0]) if self.order: return if not self.position: if self.dataclose[-1] < self.l.dch: # previous close less than the previous previous close # BUY, BUY, BUY!!! (with all possible default parameters) self.log('BUY CREATE, %.2f' % self.dataclose[0]) self.order = self.buy() else: if len(self) >= (self.bar_executed + 5): self.log("SELL CREATED {}".format(self.dataclose[0])) self.order = self.sell()
cerebro.addstrategy(DonchianChannels)
cerebro.addsizer(bt.sizers.FixedSize, stake=1000)
print("Starting Portfolio :%.2f" % cerebro.broker.getvalue())
cerebro.run()
print("Final Portfolio Value:%.2f" % cerebro.broker.getvalue())
cerebro.plot(style="candlestick",barup='green', bardown='red')