Posts made by brettelliot
RE: I'm having trouble buying on open/ selling on close using daysteps
OK that makes sense. What's the right way to use daily data and make two trades... one buys at the open price and the other sells at the closing price?
How to change data source of a data feed every day
Let's say I want to trade US stocks based on earnings announcements. This means there are approximately 5000 stocks in the universe. My current understanding of BT is that to backtest or trade a strategy that uses earnings announcements for any of the stocks in the universe I have to setup a data feed for each stock. That's a lot of data feeds!
In this post Add and remove data feeds on the flyt there is some hope...
"nothing prevents a feed from switching to delivering data from a different underlying source."
Is there an example of this anywhere?
Here's what I'm thinking... I pre-create a certain number of data feeds (say 5) and everyday I get the list of announcements, pick 5 that are interesting, and attach each to one of the data sources.
I would have to liquidate on close every night which is fine. I also understand indicators won't work, which is also fine. Anything else I should be aware of?
RE: I'm having trouble buying on open/ selling on close using daysteps
I continued searching for answers and I came across
It sort of works but I'm still not sure I'm doing this right.
This does let my sell order use the close price BUT it sells on the next day. The logs are in the right order here though and you can see it sells at the right price ($41.37) but on the 9th instead of the 8th.
2014-12-05, SELL CREATE, 41.93 2014-12-08, SELL EXECUTED, Price: 41.93, Cost: 42.02, Comm 0.04 2014-12-08, OPERATION PROFIT, GROSS -0.09, NET -0.17 0236,0471,0236,0236,2014-12-08T23:59:59.999989,41.91,41.91 2014-12-08, BUY CREATE, 41.91 2014-12-08, BUY EXECUTED, Price: 41.91, Cost: 41.91, Comm 0.04 0236,0472,0236,0236,2014-12-08T23:59:59.999989,41.91,41.37 2014-12-08, SELL CREATE, 41.37 2014-12-09, SELL EXECUTED, Price: 41.37, Cost: 41.91, Comm 0.04 2014-12-09, OPERATION PROFIT, GROSS -0.54, NET -0.62
I'm having trouble buying on open/ selling on close using daysteps
I've been gone for a few months but I'm back at it! Glad to see the community is still as active as when I went dark around April!
Anyway, I'm trying to make a strategy that buys on open using the open price and sells on close using the close price. I have daily data and i'm trying to make use of the
daysteps.pyexample and the
I sort of have it working. My strategy buys on open using the open price, and it sells on close, BUT it sells using the open price instead of the close price. I'm not sure what's going on.
First, here is a sample log (reproduced here as is, which is a bit out of order):
2014-12-08, BUY EXECUTED, Price: 41.91, Cost: 41.91, Comm 0.04 2014-12-08, SELL EXECUTED, Price: 41.91, Cost: 41.91, Comm 0.04 2014-12-08, OPERATION PROFIT, GROSS 0.00, NET -0.08 0236,0471,0236,0236,2014-12-08T23:59:59.999989,41.91,41.91 2014-12-08, BUY CREATE, 41.91 0236,0472,0236,0236,2014-12-08T23:59:59.999989,41.91,41.37 2014-12-08, SELL CREATE, 41.37
First, I issue a buy for $41.91 which is the open price. That is executed with the open price of $41.91.
Then on the closing bar of the day I issue a sell using the closing price of $41.37 and BUT it's executed using the opening price of $41.91.
I've tried futzing with the order types of the buy and sell but could not get it working.
Here is the next() function in the strategy and hopefully someone could point out my error:
def next(self): self.callcounter += 1 txtfields = list() txtfields.append('%04d' % len(self.data)) txtfields.append('%04d' % self.callcounter) txtfields.append('%04d' % len(self)) txtfields.append('%04d' % len(self.data0)) txtfields.append(self.data.datetime.datetime(0).isoformat()) txtfields.append('%.2f' % self.data0.open) txtfields.append('%.2f' % self.data0.close) print(','.join(txtfields)) if len(self.data) > self.lcontrol: self.log('BUY CREATE, %.2f' % self.dataclose) self.buy() else: self.log('SELL CREATE, %.2f' % self.dataclose) self.sell() self.lcontrol = len(self.data)
Here's all the code (which is basically daysteps with the logging code and the code to buy/ sell on open and close.
from __future__ import (absolute_import, division, print_function, unicode_literals) import datetime # For datetime objects import os.path # To manage paths import sys # To find out the script name (in argv) # Import the backtrader platform import backtrader as bt # Create a Stratey class TestStrategy(bt.Strategy): def log(self, txt, dt=None): ''' Logging function fot this strategy''' dt = dt or self.datas.datetime.date(0) print('%s, %s' % (dt.isoformat(), txt)) def __init__(self): # Keep a reference to the "close" line in the data dataseries self.dataclose = self.datas.close self.lcontrol = 0 # control if 1st or 2nd call def start(self): self.lcontrol = 0 # control if 1st or 2nd call self.callcounter = 0 def notify_order(self, order): if order.status in [order.Submitted, order.Accepted]: # Buy/Sell order submitted/accepted to/by broker - Nothing to do return # Check if an order has been completed # Attention: broker could reject order 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)) else: # Sell 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 Canceled/Margin/Rejected') def notify_trade(self, trade): if not trade.isclosed: return self.log('OPERATION PROFIT, GROSS %.2f, NET %.2f' % (trade.pnl, trade.pnlcomm)) def next(self): self.callcounter += 1 txtfields = list() txtfields.append('%04d' % len(self.data)) txtfields.append('%04d' % self.callcounter) txtfields.append('%04d' % len(self)) txtfields.append('%04d' % len(self.data0)) txtfields.append(self.data.datetime.datetime(0).isoformat()) txtfields.append('%.2f' % self.data0.open) txtfields.append('%.2f' % self.data0.close) print(','.join(txtfields)) if len(self.data) > self.lcontrol: self.log('BUY CREATE, %.2f' % self.dataclose) self.buy() else: self.log('SELL CREATE, %.2f' % self.dataclose) self.sell() self.lcontrol = len(self.data) if __name__ == '__main__': # Create a cerebro entity cerebro = bt.Cerebro() # Datas are in a subfolder of the samples. Need to find where the script is # because it could have been called from anywhere modpath = os.path.dirname(os.path.abspath(sys.argv)) datapath = os.path.join(modpath, 'orcl_2014.txt') # Create a Data Feed data = bt.feeds.YahooFinanceCSVData( dataname=datapath, # Do not pass values before this date fromdate=datetime.datetime(2014, 1, 1), # Do not pass values before this date todate=datetime.datetime(2014, 12, 31), # Do not pass values after this date reverse=False) # Add the Data Feed to Cerebro #data.addfilter(DayStepsCloseFilter) data.addfilter(bt.filters.DayStepsFilter) cerebro.adddata(data) # Add a strategy cerebro.addstrategy(TestStrategy) # Set our desired cash start cerebro.broker.setcash(100000.0) # consider a bar with the same time as the end of session to be the end of the session cerebro.broker.set_eosbar(True) # Set the commission - 0.1% ... divide by 100 to remove the % cerebro.broker.setcommission(commission=0.001) # Print out the starting conditions print('Starting Portfolio Value: %.2f' % cerebro.broker.getvalue()) # Run over everything cerebro.run() # Print out the final result print('Final Portfolio Value: %.2f' % cerebro.broker.getvalue())
Short the dip, long the correction
Thanks again for the wonderful platform and helpful community! I'm still impressed at all the great activity here! I have a trading question and I'm trying not to reinvent the wheel. Hopefully someone might be able to point me in the right direction.
Is there a "standard" or "common" approach to configure a series of trades that will short a dip and then long the correction? I'm thinking some combination of trailing stops could do this but I don't want to spend my time futzing around if there's an accepted method that people use for this purpose.
Let me give you a simple example (for illustration)... When earnings come out for a security and they are worse than analysts expected, the price goes down (dip) and often overcorrects (goes down too far) so the market starts buying and the prices go up again (correction) until it finds its happy mean.
What's the best trading strategy to capture profits on both sides? In other words, I want to short the dip and long the correction automatically.
Thanks in advance!
What's the right way to use data from API in a strategy?
Thanks again for the great platform! Having a lot of fun working with it.
I've built an indicator that reads a csv file of events and my backtest can use those events to make trades. But for live trading, I'd like to hit a JSON api for the event data.
I could call it in the strategy's next() method. Or I can do that in the indicator and use the indicator in the strategy. Or maybe I should make a feed (cause that's the only place i've seen live connections being used).
What's the preferred way to do this?
How to build a commission model for Interactive Brokers (IB)?
Thanks again for the great library! I'm just getting my feet wet but I really like it.
I needed a commission model for trading IB's US securities using their fixed rate plan. I'm sure there is one on here somewhere but it wasn't in the first few pages of search results so I wrote my own. Because of how awesome Backtrader is, it was easy to do!
Here it is for anyone else:
from __future__ import (absolute_import, division, print_function, unicode_literals) import backtrader as bt class IBCommision(bt.CommInfoBase): """A :class:`IBCommision` charges the way interactive brokers does. """ params = ( #('stocklike', True), #('commtype', bt.CommInfoBase.COMM_PERC), #('percabs', True), # Float. The amount charged per share. Ex: 0.005 means $0.005 ('per_share', 0.005), # Float. The minimum amount that will be charged. Ex: 1.0 means $1.00 ('min_per_order', 1.0), # Float. The maximum that can be charged as a percent of the trade value. Ex: 0.005 means 0.5% ('max_per_order_abs_pct', 0.005), ) def _getcommission(self, size, price, pseudoexec): """ :param size: current position size. > 0 for long positions and < 0 for short positions (this parameter will not be 0) :param price: current position price :param pseudoexec: :return: the commission of an operation at a given price """ commission = size * self.p.per_share order_price = price * size commission_as_percentage_of_order_price = commission / order_price if commission < self.p.min_per_order: commission = self.p.min_per_order elif commission_as_percentage_of_order_price > self.p.max_per_order_abs_pct: commission = order_price * self.p.max_per_order_abs_pct return commission
And here's a unit test for it:
import unittest from maroma.ibcommission import IBCommision class TestIBCommission(unittest.TestCase): def test_IBCommission(self): ib_comm = IBCommision() # test per_share commission # 1,000 Shares @ USD 25 Share Price = USD 5.00 commission = ib_comm.getcommission(1000, 25.00) self.assertEqual(commission, 5.00) # test min_per_order commission # 100 Shares @ USD 25 Share Price = USD 1.00 commission = ib_comm.getcommission(100, 25.00) self.assertEqual(commission, 1.00) # test maxPerOrderPct commission # 1,000 Shares @ USD 0.25 Share Price = USD 1.25 commission = ib_comm.getcommission(1000, .25) self.assertEqual(commission, 1.25) if __name__ == '__main__': unittest.main()