def setUp(self): """ Set up the Position object that will store the PnL. """ self.position = Position("BOT", "XIV", 4352, PriceParser.parse(15.01), PriceParser.parse(1.00), PriceParser.parse(15.01), PriceParser.parse(15.01), datetime(2011, 2, 4))
def setUp(self): """ Set up the Position object that will store the PnL. """ self.position = Position( "BOT", "SPY", 100, PriceParser.parse(239.08), PriceParser.parse(1.00), PriceParser.parse(220.45), PriceParser.parse(220.45), datetime(2016, 1, 1) )
def setUp(self): """ Set up the Position object that will store the PnL. """ self.position = Position("SLD", "SPY", 400, PriceParser.parse(244.15), PriceParser.parse(4.18), PriceParser.parse(244.05), PriceParser.parse(244.06), datetime(2016, 1, 1)) print(self.position, '\n')
def setUp(self): """ Set up the Position object that will store the PnL. """ print "Setup initial position BOT 2 ES_0_I0B at 2180.50 with $4.06 commission:" self.position = Position("BOT", "ES_0_I0B", 2, PriceParser.parse(2180.50), PriceParser.parse(4.06), PriceParser.parse(2181.50), PriceParser.parse(2181.75), datetime(2016, 1, 1)) print self.position, '\n'
def setUp(self): """ Set up the Position object that will store the PnL. """ print( "Setup initial position SLD 1 ES at 2430.50 with $2.03 commission:" ) self.position = Position("SLD", "ES", 1, PriceParser.parse(2430.50), PriceParser.parse(2.04), PriceParser.parse(2400.50), PriceParser.parse(2400.75), datetime(2016, 1, 1), mul=50) print(self.position, '\n')
def run(cache_name, cache_backend, expire_after, data_source, start, end, config, testing, tickers, filename, n, n_window): # Set up variables needed for backtest events_queue = queue.Queue() initial_equity = PriceParser.parse(500000.00) session = init_session(cache_name, cache_backend, expire_after) period = 86400 # Seconds in a day if len(tickers) == 1: data = web.DataReader(tickers[0], data_source, start, end, session=session) else: data = web.DataReader(tickers, data_source, start, end, session=session) # Use Generic Bar Handler with Pandas Bar Iterator price_event_iterator = PandasBarEventIterator(data, period, tickers[0]) price_handler = GenericPriceHandler(events_queue, price_event_iterator) # Use the Display Strategy strategy1 = DisplayStrategy(n=n, n_window=n_window) strategy2 = BuyAndHoldStrategy(tickers, events_queue) strategy = Strategies(strategy1, strategy2) # Use an example Position Sizer position_sizer = FixedPositionSizer() # Use an example Risk Manager risk_manager = ExampleRiskManager() # Use the default Portfolio Handler portfolio_handler = PortfolioHandler( initial_equity, events_queue, price_handler, position_sizer, risk_manager ) # Use the ExampleCompliance component compliance = ExampleCompliance(config) # Use a simulated IB Execution Handler execution_handler = IBSimulatedExecutionHandler( events_queue, price_handler, compliance ) # Use the default Statistics statistics = SimpleStatistics(config, portfolio_handler) # Set up the backtest backtest = Backtest( price_handler, strategy, portfolio_handler, execution_handler, position_sizer, risk_manager, statistics, initial_equity ) results = backtest.simulate_trading(testing=testing) statistics.save(filename) return results
def setUp(self): """ Set up the Portfolio object that will store the collection of Position objects, supplying it with $500,000.00 USD in initial cash. """ ph = PriceHandlerMock() cash = PriceParser.parse(500000.00) self.portfolio = Portfolio(ph, cash)
def run(config, testing, tickers, filename, n, n_window): # Set up variables needed for backtest events_queue = queue.Queue() ig_service = IGService(config.IG.USERNAME, config.IG.PASSWORD, config.IG.API_KEY, config.IG.ACCOUNT.TYPE) ig_stream_service = IGStreamService(ig_service) ig_session = ig_stream_service.create_session() accountId = ig_session[u'accounts'][0][u'accountId'] ig_stream_service.connect(accountId) initial_equity = PriceParser.parse(500000.00) # Use IG Tick Price Handler price_handler = IGTickPriceHandler(events_queue, ig_stream_service, tickers) # Use the Display Strategy strategy = DisplayStrategy(n=n, n_window=n_window) # Use an example Position Sizer position_sizer = FixedPositionSizer() # Use an example Risk Manager risk_manager = ExampleRiskManager() # Use the default Portfolio Handler portfolio_handler = PortfolioHandler(initial_equity, events_queue, price_handler, position_sizer, risk_manager) # Use the ExampleCompliance component compliance = ExampleCompliance(config) # Use a simulated IB Execution Handler execution_handler = IBSimulatedExecutionHandler(events_queue, price_handler, compliance) # Use the default Statistics statistics = SimpleStatistics(config, portfolio_handler) # Set up the backtest backtest = Backtest(price_handler, strategy, portfolio_handler, execution_handler, position_sizer, risk_manager, statistics, initial_equity) results = backtest.simulate_trading(testing=testing) statistics.save(filename) return results
def run(config, testing, tickers, filename): # Benchmark ticker benchmark = 'SP500TR' # Set up variables needed for backtest title = [ 'Moving Average Crossover Example', __file__, ','.join(tickers) + ': 100x400' ] events_queue = queue.Queue() csv_dir = config.CSV_DATA_DIR initial_equity = PriceParser.parse(500000.00) # Use Yahoo Daily Price Handler price_handler = YahooDailyCsvBarPriceHandler(csv_dir, events_queue, tickers) # Use the MAC Strategy strategy = MovingAverageCrossStrategy(tickers, events_queue) # Use an example Position Sizer, position_sizer = FixedPositionSizer() # Use an example Risk Manager, risk_manager = ExampleRiskManager() # Use the default Portfolio Handler portfolio_handler = PortfolioHandler(initial_equity, events_queue, price_handler, position_sizer, risk_manager) # Use the ExampleCompliance component compliance = ExampleCompliance(config) # Use a simulated IB Execution Handler execution_handler = IBSimulatedExecutionHandler(events_queue, price_handler, compliance) # Use the default Statistics statistics = TearsheetStatistics(config, portfolio_handler, title, benchmark) # Set up the backtest backtest = Backtest(price_handler, strategy, portfolio_handler, execution_handler, position_sizer, risk_manager, statistics, initial_equity) results = backtest.simulate_trading(testing=testing) statistics.save(filename) return results
def run(config, testing, tickers, filename): # Set up variables needed for backtest events_queue = queue.Queue() csv_dir = config.CSV_DATA_DIR initial_equity = PriceParser.parse(500000.00) # Use Historic CSV Price Handler price_handler = HistoricCSVTickPriceHandler( csv_dir, events_queue, tickers ) # Use the Example Strategy strategy = ExampleStrategy(tickers, events_queue) # Use an example Position Sizer position_sizer = FixedPositionSizer() # Use an example Risk Manager risk_manager = ExampleRiskManager() # Use the default Portfolio Handler portfolio_handler = PortfolioHandler( initial_equity, events_queue, price_handler, position_sizer, risk_manager ) # Use the ExampleCompliance component compliance = ExampleCompliance(config) # Use a simulated IB Execution Handler execution_handler = IBSimulatedExecutionHandler( events_queue, price_handler, compliance ) # Use the default Statistics statistics = SimpleStatistics(config, portfolio_handler) # Set up the backtest backtest = Backtest( price_handler, strategy, portfolio_handler, execution_handler, position_sizer, risk_manager, statistics, initial_equity ) results = backtest.simulate_trading(testing=testing) statistics.save(filename) return results
def test_transact_position(self): """ Update market value of current position """ print("Update market value with bid/ask of 2423.75.00/2424.00:") self.position.update_market_value(PriceParser.parse(2423.75), PriceParser.parse(2424.00), datetime(2016, 1, 2)) print(self.position, '\n') self.assertEqual(self.position.action, "SLD") self.assertEqual(self.position.ticker, "ES") self.assertEqual(self.position.quantity, 1) self.assertEqual(self.position.open_quantity, 1) self.assertEqual(PriceParser.display(self.position.entry_price, 5), round((2430.50 * 50 - 2.04) / 50, 5)) self.assertEqual(PriceParser.display(self.position.exit_price, 5), 0) self.assertEqual(PriceParser.display(self.position.total_commission), 2.04) self.assertEqual(PriceParser.display(self.position.cost_basis), -50 * 2430.50 + 2.04) self.assertEqual(PriceParser.display(self.position.market_value), -50 * 2424.00, 2) self.assertEqual( PriceParser.display(self.position.unrealised_pnl), round((50 * 2424.00 * -1) - (50 * 2430.50 * -1 + 2.04), 2), 2) self.assertEqual(PriceParser.display(self.position.realised_pnl), 0.00) print( "Sell 3 ES @ 2422.75 with $6.12 commission. Update market value with bid/ask of 2420.75/2421.00:" ) self.position.transact_shares("SLD", 3, PriceParser.parse(2422.75), PriceParser.parse(6.12)) self.position.update_market_value(PriceParser.parse(2420.75), PriceParser.parse(2421.00), datetime(2016, 1, 3)) print(self.position, '\n') print(self.position.bots, self.position.solds) self.assertEqual(self.position.action, "SLD") self.assertEqual(self.position.ticker, "ES") self.assertEqual(self.position.quantity, 4) self.assertEqual(self.position.open_quantity, 4) self.assertEqual( PriceParser.display(self.position.entry_price, 5), round((2430.50 * 50 - 2.04 + 3 * 2422.75 * 50 - 6.12) / 4 / 50, 5)) self.assertEqual(PriceParser.display(self.position.exit_price, 5), 0) self.assertEqual(PriceParser.display(self.position.total_commission), 2.04 + 6.12) self.assertEqual(PriceParser.display(self.position.cost_basis), (-50 * 2430.50 + 2.04) + (-3 * 50 * 2422.75 + 6.12)) self.assertEqual(PriceParser.display(self.position.market_value), -4 * 50 * 2421.00, 2) self.assertEqual( PriceParser.display(self.position.unrealised_pnl), round((-4 * 50 * 2421.00) - ((-50 * 2430.50 + 2.04) + (-3 * 50 * 2422.75 + 6.12)), 2), 2) self.assertEqual(PriceParser.display(self.position.realised_pnl), 0.00)
def test_calculate_round_trip(self): """ After the subsequent purchase, carry out two more buys/longs and then close the position out with two additional sells/shorts. """ print( "Sell 400 SPY at 244.15 with $4.18 commission. Update market value with bid/ask of 244.05/244.06:" ) self.position.update_market_value(PriceParser.parse(244.05), PriceParser.parse(244.06), datetime(2016, 1, 2)) print(self.position, '\n') self.assertEqual(self.position.action, "SLD") self.assertEqual(self.position.ticker, "SPY") self.assertEqual(self.position.quantity, 400) self.assertEqual(self.position.open_quantity, 400) self.assertEqual(PriceParser.display(self.position.entry_price, 5), (244.15 * 400 - 4.18) / 400) self.assertEqual(PriceParser.display(self.position.exit_price, 5), 0) self.assertEqual(PriceParser.display(self.position.total_commission), 4.18) self.assertEqual(PriceParser.display(self.position.cost_basis), -1 * 244.15 * 400 + 4.18) self.assertEqual(PriceParser.display(self.position.market_value), -1 * 244.06 * 400, 2) self.assertEqual( PriceParser.display(self.position.unrealised_pnl), round((-1 * 244.06 * 400) - (-1 * 244.15 * 400 + 4.18), 2), 2) self.assertEqual(PriceParser.display(self.position.realised_pnl), 0.00) print( "Sell 250 SPY at 243.88 with $2.61 commission. Update market value with bid/ask of 243.47/243.48:" ) self.position.transact_shares("SLD", 250, PriceParser.parse(243.88), PriceParser.parse(2.61)) self.position.update_market_value(PriceParser.parse(243.47), PriceParser.parse(243.48), datetime(2016, 1, 3)) print(self.position, '\n') self.assertEqual(self.position.action, "SLD") self.assertEqual(self.position.ticker, "SPY") self.assertEqual(self.position.quantity, 400 + 250) self.assertEqual(self.position.open_quantity, 400 + 250) self.assertEqual( PriceParser.display(self.position.entry_price, 5), round((244.15 * 400 + 4.18 + 243.88 * 250 + 2.61) / 650, 5)) self.assertEqual(PriceParser.display(self.position.exit_price, 5), 0) self.assertEqual(PriceParser.display(self.position.total_commission), round(4.18 + 2.61, 2)) self.assertEqual( PriceParser.display(self.position.cost_basis), round(-1 * 244.15 * 400 + 4.18 - 1 * 243.88 * 250 + 2.61, 2)) self.assertEqual(PriceParser.display(self.position.market_value), -1 * 243.48 * 650, 2) self.assertEqual( PriceParser.display(self.position.unrealised_pnl), round((-1 * 243.48 * 650) - (-1 * 244.15 * 400 + 4.18 - 1 * 243.88 * 250 + 2.61), 2), 2) self.assertEqual(PriceParser.display(self.position.realised_pnl), 0.00) print( "Sell 150 SPY at 243.50 with $1.81 commission. Update market value with bid/ask of 243.50/243.51:" ) self.position.transact_shares("SLD", 150, PriceParser.parse(243.50), PriceParser.parse(1.81)) self.position.update_market_value(PriceParser.parse(243.50), PriceParser.parse(243.51), datetime(2016, 1, 4)) print(self.position, '\n') print("bots:", self.position.bots) print("solds:", self.position.solds) self.assertEqual(self.position.action, "SLD") self.assertEqual(self.position.ticker, "SPY") self.assertEqual(self.position.quantity, 400 + 250 + 150) self.assertEqual(self.position.open_quantity, 400 + 250 + 150) self.assertEqual( PriceParser.display(self.position.entry_price, 5), round((244.15 * 400 + 4.18 + 243.88 * 250 + 2.61 + 243.50 * 150 + 1.81) / 800, 5)) self.assertEqual(PriceParser.display(self.position.exit_price, 5), 0) self.assertEqual(PriceParser.display(self.position.total_commission), round(4.18 + 2.61 + 1.81, 2)) self.assertEqual( PriceParser.display(self.position.cost_basis), round( -1 * 244.15 * 400 + 4.18 - 1 * 243.88 * 250 + 2.61 - 1 * 243.50 * 150 + 1.81, 2)) self.assertEqual(PriceParser.display(self.position.market_value), -1 * 243.51 * 800, 2) self.assertEqual( PriceParser.display(self.position.unrealised_pnl), round((-1 * 243.51 * 800) - (-1 * 244.15 * 400 + 4.18 - 1 * 243.88 * 250 + 2.61 - 1 * 243.50 * 150 + 1.81), 2), 2) self.assertEqual(PriceParser.display(self.position.realised_pnl), 0.00) print( "Buy 50 SPY at 243.77 with $1.00 commission. Update market value with bid/ask of 243.84/243.86:" ) self.position.transact_shares("BOT", 50, PriceParser.parse(243.77), PriceParser.parse(1.00)) self.position.update_market_value(PriceParser.parse(243.84), PriceParser.parse(243.86), datetime(2016, 1, 5)) print(self.position, '\n') self.assertEqual(self.position.action, "SLD") self.assertEqual(self.position.ticker, "SPY") self.assertEqual(self.position.quantity, 400 + 250 + 150) self.assertEqual(self.position.open_quantity, 400 + 250 + 150 - 50) self.assertEqual( PriceParser.display(self.position.entry_price, 5), round((244.15 * 400 + 4.18 + 243.88 * 250 + 2.61 + 243.50 * 150 + 1.81) / 800, 5)) self.assertEqual(PriceParser.display(self.position.exit_price, 5), (243.77 * 50 + 1) / 50) self.assertEqual(PriceParser.display(self.position.total_commission), round(4.18 + 2.61 + 1.81 + 1, 2)) self.assertEqual( PriceParser.display(self.position.cost_basis), round( -1 * 244.15 * 350 + 350 / 400 * 4.18 - 1 * 243.88 * 250 + 2.61 - 1 * 243.50 * 150 + 1.81, 4)) self.assertEqual(PriceParser.display(self.position.market_value), -1 * 243.86 * 750, 2) self.assertEqual( PriceParser.display(self.position.unrealised_pnl), round((-1 * 243.86 * 750) - (-1 * 244.15 * 350 + 350 / 400 * 4.18 - 1 * 243.88 * 250 + 2.61 - 1 * 243.50 * 150 + 1.81), 4)) self.assertEqual(PriceParser.display(self.position.realised_pnl), 17.4775) print( "Buy 750 SPY at 244.29 with $3.75 commission. Update market value with bid/ask of 243.84/243.86:" ) self.position.transact_shares("BOT", 750, PriceParser.parse(244.29), PriceParser.parse(3.75)) self.position.update_market_value(PriceParser.parse(243.29), PriceParser.parse(243.29), datetime(2016, 1, 6)) print(self.position, '\n') print("bots:", self.position.bots) print("solds:", self.position.solds) self.assertEqual(self.position.action, "SLD") self.assertEqual(self.position.ticker, "SPY") self.assertEqual(self.position.quantity, 400 + 250 + 150) self.assertEqual(self.position.open_quantity, 400 + 250 + 150 - 50 - 750) self.assertEqual( PriceParser.display(self.position.entry_price, 5), round((244.15 * 400 + 4.18 + 243.88 * 250 + 2.61 + 243.50 * 150 + 1.81) / 800, 5)) self.assertEqual( PriceParser.display(self.position.exit_price, 5), round((243.77 * 50 + 1 + 244.29 * 750 + 3.75) / 800, 5)) self.assertEqual(PriceParser.display(self.position.total_commission), round(4.18 + 2.61 + 1.81 + 1 + 3.75, 2)) self.assertEqual(PriceParser.display(self.position.cost_basis), 0) self.assertEqual(PriceParser.display(self.position.market_value), 0) self.assertEqual(PriceParser.display(self.position.unrealised_pnl), 0) self.assertEqual(PriceParser.display(self.position.realised_pnl), -264.35)
def test_transact_position(self): """ Update market value of current position """ print "Update market value with bid/ask of 2178.50/2178.75:" self.position.update_market_value(PriceParser.parse(2190.00), PriceParser.parse(2190.25), datetime(2016, 1, 2)) print self.position, '\n' self.assertEqual(self.position.action, "BOT") self.assertEqual(self.position.ticker, "ES_0_I0B") self.assertEqual(self.position.quantity, 2) self.assertEqual(self.position.buys, 2) self.assertEqual(self.position.sells, 0) self.assertEqual(self.position.net, 2) self.assertEqual(PriceParser.display(self.position.avg_bot, 5), 2180.50) self.assertEqual(PriceParser.display(self.position.avg_sld, 5), 0) self.assertEqual(PriceParser.display(self.position.total_bot), 218050.00) self.assertEqual(PriceParser.display(self.position.total_sld), 0.0) self.assertEqual(PriceParser.display(self.position.net_total), 218050.00) self.assertEqual(PriceParser.display(self.position.total_commission), 4.06) self.assertEqual(PriceParser.display(self.position.net_incl_comm), 218050.00 - 4.06) self.assertEqual(PriceParser.display(self.position.avg_price, 5), (218050.00 - 4.06) / 2 / 50) self.assertEqual(PriceParser.display(self.position.cost_basis), 218050 - 4.06) self.assertEqual(PriceParser.display(self.position.market_value), (2190 + 2190.25) / 2 * 2 * 50) self.assertEqual( PriceParser.display(self.position.unrealised_pnl), round((((2190 + 2190.25) / 2 * 2 * 50) - (218050 - 4.06)), 2) * 1) self.assertEqual(PriceParser.display(self.position.realised_pnl), 0.00) print "Sell 1 contract of current position at 2187.50 with 2.03 commission. Market at 2193.50/2193.50:" self.position.transact_shares("SLD", 1, PriceParser.parse(2187.50), PriceParser.parse(2.03)) self.position.update_market_value(PriceParser.parse(2193.50), PriceParser.parse(2193.50), datetime(2016, 1, 3)) print self.position, '\n' self.assertEqual(self.position.quantity, 1) self.assertEqual(self.position.buys, 2) self.assertEqual(self.position.sells, 1) self.assertEqual(self.position.net, 1) self.assertEqual(PriceParser.display(self.position.avg_bot, 5), 2180.50) self.assertEqual(PriceParser.display(self.position.avg_sld, 5), 2187.50) self.assertEqual(PriceParser.display(self.position.total_bot), 218050.00) self.assertEqual(PriceParser.display(self.position.total_sld), 2187.5 * 50) self.assertEqual(PriceParser.display(self.position.net_total), (2187.5 * 50) - 218050.00) self.assertEqual(PriceParser.display(self.position.total_commission), 6.09) self.assertEqual(PriceParser.display(self.position.net_incl_comm), (2187.5 * 50) - 218050.00 - 6.09) self.assertEqual(PriceParser.display(self.position.avg_price, 5), (218050.00 - 4.06) / 2 / 50) self.assertEqual(PriceParser.display(self.position.cost_basis), round(1 * (218050.00 - 4.06) / 2 / 50 * 50, 2)) self.assertEqual(PriceParser.display(self.position.market_value), (2193.50 + 2193.50) / 2 * 1 * 50) self.assertEqual(PriceParser.display(self.position.unrealised_pnl), 652.03) self.assertEqual(PriceParser.display(self.position.realised_pnl), 347.97) print "Sell 1 contract TO CLOSE position at 2199.00 with 2.03 commission. Market at 2199.50/2199.75:" self.position.transact_shares("SLD", 1, PriceParser.parse(2199.00), PriceParser.parse(2.03)) self.position.update_market_value(PriceParser.parse(2199.50), PriceParser.parse(2199.75), datetime(2016, 1, 3)) print self.position, '\n'
def test_initial_bot(self): """ After the subsequent purchase, carry out two more buys/longs and then close the position out with two additional sells/shorts. """ print("Buy 100 SPY at 239.08 with $1.00 commission. Update market value with bid/ask of 239.95/239.96:") self.position.update_market_value( PriceParser.parse(239.95), PriceParser.parse(239.96), datetime(2016, 1, 2) ) print(self.position, '\n') self.assertIs(type(self.position.quantity), int) self.assertIs(type(self.position.open_quantity), int) self.assertIs(type(self.position.mul), int) self.assertIs(type(self.position.realised_pnl), int) self.assertIs(type(self.position.unrealised_pnl), int) self.assertIs(type(self.position.entry_price), int) self.assertIs(type(self.position.exit_price), int) self.assertIs(type(self.position.total_commission), int) self.assertIs(type(self.position.market_value), int) self.assertIs(type(self.position.cost_basis), int) print("Buy 300 shares to add to current position at 238.90 with 1.50 commission. Market at 238.96/238.97:") self.position.transact_shares( "BOT", 300, PriceParser.parse(238.90), PriceParser.parse(1.50) ) self.position.update_market_value( PriceParser.parse(238.96), PriceParser.parse(238.97), datetime(2016, 1, 3) ) print(self.position, '\n') self.assertIs(type(self.position.quantity), int) self.assertIs(type(self.position.open_quantity), int) self.assertIs(type(self.position.mul), int) self.assertIs(type(self.position.realised_pnl), int) self.assertIs(type(self.position.unrealised_pnl), int) self.assertIs(type(self.position.entry_price), int) self.assertIs(type(self.position.exit_price), int) self.assertIs(type(self.position.total_commission), int) self.assertIs(type(self.position.market_value), int) self.assertIs(type(self.position.cost_basis), int) print("Sell 150 shares from current position at 239.05 with 1.80 commission. Market at 239.19/239.20:") self.position.transact_shares( "SLD", 150, PriceParser.parse(239.05), PriceParser.parse(1.80) ) self.position.update_market_value( PriceParser.parse(239.19), PriceParser.parse(239.20), datetime(2016, 1, 4) ) print(self.position, '\n') self.assertIs(type(self.position.quantity), int) self.assertIs(type(self.position.open_quantity), int) self.assertIs(type(self.position.mul), int) self.assertIs(type(self.position.realised_pnl), int) self.assertIs(type(self.position.unrealised_pnl), int) self.assertIs(type(self.position.entry_price), int) self.assertIs(type(self.position.exit_price), int) self.assertIs(type(self.position.total_commission), int) self.assertIs(type(self.position.market_value), int) self.assertIs(type(self.position.cost_basis), int) print("Sell 250 shares to close position at 244.09 with 5.22 commission. Market at 244.09/244.10:") self.position.transact_shares( "SLD", 250, PriceParser.parse(244.09), PriceParser.parse(5.22) ) self.position.update_market_value( PriceParser.parse(244.09), PriceParser.parse(244.10), datetime(2016, 1, 6) ) print(self.position, '\n') self.assertIs(type(self.position.quantity), int) self.assertIs(type(self.position.open_quantity), int) self.assertIs(type(self.position.mul), int) self.assertIs(type(self.position.realised_pnl), int) self.assertIs(type(self.position.unrealised_pnl), int) self.assertIs(type(self.position.entry_price), int) self.assertIs(type(self.position.exit_price), int) self.assertIs(type(self.position.total_commission), int) self.assertIs(type(self.position.market_value), int) self.assertIs(type(self.position.cost_basis), int)
def run(config, testing, tickers): # Benchmark ticker benchmark = None bt_start_dt = datetime(2000, 4, 1) trd_start_dt = datetime(2000, 4, 1) end_dt = datetime(2000, 12, 31) #start_dt = datetime(2016, 1, 1) #end_dt = datetime(2016, 8, 1) # Set up variables needed for backtest title = [ 'RSI2', path.basename(__file__), ','.join(tickers) ] events_queue = queue.Queue() sqlite_db = config.SQLITE_DB initial_equity = PriceParser.parse(100000.00) # Use Sqlite Daily Price Handler price_handler = SqliteBarPriceHandler( sqlite_db, events_queue, tickers ) # Use the RSI Strategy strategy = RSI2Strategy(config, tickers, events_queue) # Use fixed Position Sizer, position_sizer = FixedPositionSizer() # Use an example Risk Manager, risk_manager = ExampleRiskManager() # Use the default Portfolio Handler portfolio_handler = PortfolioHandler( initial_equity, events_queue, price_handler, position_sizer, risk_manager ) # Use the ExampleCompliance component compliance = ExampleCompliance(config) # Use a simulated IB Execution Handler execution_handler = IBSimulatedExecutionHandler( events_queue, price_handler, compliance ) # Use the default Statistics # statistics = BasicStatistics( # config, portfolio_handler # ) statistics = TearsheetStatistics( config, portfolio_handler, title, benchmark, trd_start_dt, end_dt ) # Set up the backtest backtest = Backtest( price_handler, strategy, portfolio_handler, execution_handler, position_sizer, risk_manager, statistics, initial_equity, bt_start_dt, end_dt ) results = backtest.simulate_trading(testing=testing) return results
def test_calculate_round_trip(self): """ Purchase/sell multiple lots of AMZN and GOOG at various prices/commissions to check the arithmetic and cost handling. """ self.portfolio.transact_position( "SLD", "AMZN", 100, PriceParser.parse(566.56), PriceParser.parse(1.00) ) # Buy 300 of AMZN over two transactions self.portfolio.transact_position( "BOT", "AMZN", 100, PriceParser.parse(566.56), PriceParser.parse(1.00) ) self.portfolio.transact_position( "BOT", "AMZN", 200, PriceParser.parse(566.395), PriceParser.parse(1.00) ) # Buy 200 GOOG over one transaction self.portfolio.transact_position( "BOT", "GOOG", 200, PriceParser.parse(707.50), PriceParser.parse(1.00) ) # Add to the AMZN position by 100 shares self.portfolio.transact_position( "SLD", "AMZN", 100, PriceParser.parse(565.83), PriceParser.parse(1.00) ) # Add to the GOOG position by 200 shares self.portfolio.transact_position( "BOT", "GOOG", 200, PriceParser.parse(705.545), PriceParser.parse(1.00) ) # Sell 200 of the AMZN shares self.portfolio.transact_position( "SLD", "AMZN", 200, PriceParser.parse(565.59), PriceParser.parse(1.00) ) # Multiple transactions bundled into one (in IB) # Sell 300 GOOG from the portfolio self.portfolio.transact_position( "SLD", "GOOG", 100, PriceParser.parse(704.92), PriceParser.parse(1.00) ) self.portfolio.transact_position( "SLD", "GOOG", 100, PriceParser.parse(704.90), PriceParser.parse(0.00) ) self.portfolio.transact_position( "SLD", "GOOG", 100, PriceParser.parse(704.92), PriceParser.parse(0.50) ) # Finally, sell the remaining GOOG 100 shares self.portfolio.transact_position( "SLD", "GOOG", 100, PriceParser.parse(704.78), PriceParser.parse(1.00) ) # The figures below are derived from Interactive Brokers # demo account using the above trades with prices provided # by their demo feed. self.assertEqual(len(self.portfolio.positions), 0) self.assertEqual(len(self.portfolio.closed_positions), 2) self.assertEqual(PriceParser.display(self.portfolio.cur_cash), 499100.50) self.assertEqual(PriceParser.display(self.portfolio.equity), 499100.50) self.assertEqual(PriceParser.display(self.portfolio.unrealised_pnl), 0.00) self.assertEqual(PriceParser.display(self.portfolio.realised_pnl), -899.50)
def calculate_signals(self, event): ticker = self.tickers[0] if event.type == EventType.BAR and event.ticker == ticker: d = OrderedDict() d['timestamp'] = event.time d['sig_ticker'] = ticker d['sig_close'] = PriceParser.display(event.close_price) d['trend'] = None d['rsi'] = None self.bars.loc[event.time] = (event.open_price, event.high_price, event.low_price, event.close_price) # Enough bars are present for trading if len(self.bars) > 3: trend = self.calc_trend(self.bars) rsi = RSI(self.bars['close']) d['trend'] = trend d['rsi'] = rsi # print ("Date: %s Ticker: %s Trend: %s RSI: %0.4f" % ( # event.time, ticker, trend, rsi) # ) # Process Exit Signals if self.position == 'LE' and rsi > 50: signal = SignalEvent(ticker, "SLD") self.events_queue.put(signal) self.position = 'OUT' print "%s Signal:LX %s trend:%s rsi:%0.4f" % ( event.time, ticker, trend, rsi) if self.position == 'SE' and rsi < 50: signal = SignalEvent(ticker, "BOT") self.events_queue.put(signal) self.position = 'OUT' print "%s Signal:SX %s trend:%s rsi:%0.4f" % ( event.time, ticker, trend, rsi) # Entry Signals if self.position == 'OUT': # LE if rsi < 50: signal = SignalEvent(ticker, "BOT") self.events_queue.put(signal) self.position = 'LE' print "%s Signal:LE %s trend:%s rsi:%0.4f" % ( event.time, ticker, trend, rsi) # SE if rsi > 50: signal = SignalEvent(ticker, "SLD") self.events_queue.put(signal) self.position = 'SE' print "%s Signal:SE %s trend:%s rsi:%0.4f" % ( event.time, ticker, trend, rsi) # Write explore d['position'] = self.position self.record_explore(d)
def test_calculate_round_trip(self): """ After the subsequent purchase, carry out two more buys/longs and then close the position out with two additional sells/shorts. """ print("Buy 100 SPY at 239.08 with $1.00 commission. Update market value with bid/ask of 239.95/239.96:") self.position.update_market_value( PriceParser.parse(239.95), PriceParser.parse(239.96), datetime(2016, 1, 2) ) print(self.position, '\n') self.assertEqual(self.position.action, "BOT") self.assertEqual(self.position.ticker, "SPY") self.assertEqual(self.position.quantity, 100) self.assertEqual(self.position.open_quantity, 100) self.assertEqual(PriceParser.display(self.position.entry_price, 5), (239.08*100 + 1)/100) self.assertEqual(PriceParser.display(self.position.exit_price, 5), 0) self.assertEqual(PriceParser.display(self.position.total_commission), 1.00) self.assertEqual(PriceParser.display(self.position.cost_basis), 239.08*100 + 1.00) self.assertEqual(PriceParser.display(self.position.market_value), 239.95*100 * 1, 2) self.assertEqual(PriceParser.display(self.position.unrealised_pnl), (239.95*100 * 1) - (239.08*100 + 1.00), 2) self.assertEqual(PriceParser.display(self.position.realised_pnl), 0.00) print("Buy 300 shares to add to current position at 238.90 with 1.50 commission. Market at 238.96/238.97:") self.position.transact_shares( "BOT", 300, PriceParser.parse(238.90), PriceParser.parse(1.50) ) self.position.update_market_value( PriceParser.parse(238.96), PriceParser.parse(238.97), datetime(2016, 1, 3) ) print(self.position, '\n') self.assertEqual(self.position.quantity, 400) self.assertEqual(self.position.open_quantity, 400) self.assertEqual(PriceParser.display(self.position.entry_price, 5), (239.08*100+1 + 238.90*300+1.5)/400) self.assertEqual(PriceParser.display(self.position.exit_price, 5), 0) self.assertEqual(PriceParser.display(self.position.total_commission), 2.50) self.assertEqual(PriceParser.display(self.position.cost_basis), (239.08*100+1 + 238.90*300+1.5)) self.assertEqual(PriceParser.display(self.position.market_value), 238.96 * 400, 2) self.assertEqual(PriceParser.display(self.position.unrealised_pnl), (238.96 * 400) - (239.08*100+1 + 238.90*300+1.5), 2) self.assertEqual(PriceParser.display(self.position.realised_pnl), 0.00) print("Sell 150 shares from current position at 239.05 with 1.80 commission. Market at 239.19/239.20:") self.position.transact_shares( "SLD", 150, PriceParser.parse(239.05), PriceParser.parse(1.80) ) self.position.update_market_value( PriceParser.parse(239.19), PriceParser.parse(239.20), datetime(2016, 1, 4) ) print(self.position, '\n') self.assertEqual(self.position.quantity, 400) self.assertEqual(self.position.open_quantity, 100+300-150) self.assertEqual(PriceParser.display(self.position.entry_price, 5), (239.08*100+1 + 238.90*300+1.5)/400) self.assertEqual(PriceParser.display(self.position.exit_price, 5), (239.05*150+1.80)/150) self.assertEqual(PriceParser.display(self.position.total_commission), 4.30) self.assertEqual(PriceParser.display(self.position.cost_basis), (238.90*250)+(250/300*1.5)) self.assertEqual(PriceParser.display(self.position.market_value), 239.19 * 250) self.assertEqual(PriceParser.display(self.position.unrealised_pnl), (239.19 * 250) - ((238.90*250)+(250/300*1.5)), 2) self.assertEqual(PriceParser.display(self.position.realised_pnl), 1.45) print("Buy 250 shares adding to current position at 239.39 with 1.25 commission. Market at 245.24/245.25:") self.position.transact_shares( "BOT", 250, PriceParser.parse(239.39), PriceParser.parse(1.25) ) self.position.update_market_value( PriceParser.parse(245.24), PriceParser.parse(245.25), datetime(2016, 1, 5) ) print(self.position, '\n') self.assertEqual(self.position.quantity, 650) self.assertEqual(self.position.open_quantity, 100+300-150+250) self.assertEqual(PriceParser.display(self.position.entry_price, 5), round((239.08*100+1 + 238.90*300+1.5 + 239.39*250+1.25)/650, 5)) self.assertEqual(PriceParser.display(self.position.exit_price, 5), (239.05*150+1.80)/150) self.assertEqual(PriceParser.display(self.position.total_commission), 5.55) self.assertEqual(PriceParser.display(self.position.cost_basis), (238.90*250)+(250/300*1.5)+(239.39*250+1.25)) self.assertEqual(PriceParser.display(self.position.market_value), 245.24 * 500) self.assertEqual(PriceParser.display(self.position.unrealised_pnl), (245.24 * 500) - ((238.90*250)+(250/300*1.5)+(239.39*250+1.25)), 2) self.assertEqual(PriceParser.display(self.position.realised_pnl), 1.45) print("Sell 500 shares to close position at 244.09 with 5.22 commission. Market at 244.09/244.10:") self.position.transact_shares( "SLD", 500, PriceParser.parse(244.09), PriceParser.parse(5.22) ) self.position.update_market_value( PriceParser.parse(244.09), PriceParser.parse(244.10), datetime(2016, 1, 6) ) print(self.position, '\n') self.assertEqual(self.position.quantity, 650) self.assertEqual(self.position.open_quantity, 100+300-150+250-500) self.assertEqual(PriceParser.display(self.position.entry_price, 5), round((239.08*100+1 + 238.90*300+1.5 + 239.39*250+1.25)/650, 5)) self.assertEqual(PriceParser.display(self.position.exit_price, 5), round((239.05*150+1.80 + 244.09*500+5.22)/(150+500), 5)) self.assertEqual(PriceParser.display(self.position.total_commission), 5.55+5.22) self.assertEqual(PriceParser.display(self.position.cost_basis), 0) self.assertEqual(PriceParser.display(self.position.market_value), 0) self.assertEqual(PriceParser.display(self.position.unrealised_pnl), 0) self.assertEqual(PriceParser.display(self.position.realised_pnl), round(1.45+(244.09-238.90)*250-250/300*1.5+(244.09-239.39)*250-1.25-5.22, 2))
def get_best_bid_ask(self, ticker): prices = { "GOOG": (PriceParser.parse(705.46), PriceParser.parse(705.46)), "AMZN": (PriceParser.parse(564.14), PriceParser.parse(565.14)), } return prices[ticker]
def test_enter_long_position(self): """ Initial entry """ print( "Buy 4352 XIV at 15.01 with $1.00 commission. Update market value with bid/ask of 15.01/15.01:" ) self.position.update_market_value(PriceParser.parse(15.01), PriceParser.parse(15.01), datetime(2011, 2, 4)) print(self.position, '\n') self.assertEqual(self.position.action, "BOT") self.assertEqual(self.position.ticker, "XIV") self.assertEqual(self.position.quantity, 4352) self.assertEqual(self.position.buys, 4352) self.assertEqual(self.position.sells, 0) self.assertEqual(self.position.net, 4352) self.assertEqual(PriceParser.display(self.position.avg_bot, 5), 15.01) self.assertEqual(PriceParser.display(self.position.avg_sld, 5), 0) self.assertEqual(PriceParser.display(self.position.total_bot), 15.01 * 4352) self.assertEqual(PriceParser.display(self.position.total_sld), 0) self.assertEqual(PriceParser.display(self.position.net_total), 15.01 * 4352) self.assertEqual(PriceParser.display(self.position.total_commission), 1.00) self.assertEqual(PriceParser.display(self.position.net_incl_comm), 15.01 * 4352 - 1.00) self.assertEqual(PriceParser.display(self.position.avg_price, 5), round((15.01 * 4352 + 1.00) / 4352 / 1, 5)) self.assertEqual(PriceParser.display(self.position.cost_basis, 2), 15.01 * 4352 + 1.00) self.assertEqual(PriceParser.display(self.position.market_value), round(((15.01 + 15.01) / 2 * 4352 * 1), 2)) self.assertEqual( PriceParser.display(self.position.unrealised_pnl, 2), round(((15.01 + 15.01) / 2 * 4352 * 1) - (15.01 * 4352 + 1.00), 2)) self.assertEqual(PriceParser.display(self.position.realised_pnl, 2), 0.00) print( "Sell 2188 shares of current position at 15.24 with 1.00 commission. Market at 15.24/15.24:" ) self.position.transact_shares("SLD", 2188, PriceParser.parse(15.24), PriceParser.parse(1.00)) self.position.update_market_value(PriceParser.parse(15.24), PriceParser.parse(15.24), datetime(2011, 2, 7)) print(self.position, '\n') self.assertEqual(self.position.buys, 4352) self.assertEqual(self.position.sells, 2188) self.assertEqual(self.position.net, 4352 - 2188) self.assertEqual(PriceParser.display(self.position.avg_bot, 5), round((15.01 * 4352) / 4352, 5)) self.assertEqual(PriceParser.display(self.position.avg_sld, 5), round((15.24 * 2188) / 2188, 5)) self.assertEqual(PriceParser.display(self.position.total_bot), 15.01 * 4352) self.assertEqual(PriceParser.display(self.position.total_sld), 15.24 * 2188) self.assertEqual(PriceParser.display(self.position.net_total), round(15.24 * 2188 - (15.01 * 4352), 2)) self.assertEqual(PriceParser.display(self.position.total_commission), 2.00) self.assertEqual(PriceParser.display(self.position.net_incl_comm), round(((15.24 * 2188) - (15.01 * 4352)) - 2.00, 2)) self.assertEqual(PriceParser.display(self.position.avg_price, 5), round((15.01 * 4352 + 1) / 4352, 5)) self.assertEqual(PriceParser.display(self.position.cost_basis, 2), 32482.14) #15.01*(4352-2188) + 1) self.assertEqual(PriceParser.display(self.position.market_value), round((15.24 * (4352 - 2188) * 1), 2)) self.assertEqual(PriceParser.display(self.position.unrealised_pnl, 2), round((15.24 * (4352 - 2188) * 1) - (32482.14), 2)) self.assertEqual(PriceParser.display(self.position.realised_pnl), (15.24 - 15.01) * 2188 - 2) print( "Sell 75 shares from current position at 220.85 with 1.37 commission. Market at 220.85/220.86:" ) self.position.transact_shares("SLD", 75, PriceParser.parse(220.85), PriceParser.parse(1.37)) self.position.update_market_value(PriceParser.parse(220.85), PriceParser.parse(220.86), datetime(2016, 1, 3)) print(self.position, '\n') self.assertEqual(self.position.buys, 150) self.assertEqual(self.position.sells, 75) self.assertEqual(self.position.net, 75) self.assertEqual(PriceParser.display(self.position.avg_bot, 5), round((220.45 * 100 + 220.35 * 50) / 150, 5)) self.assertEqual(PriceParser.display(self.position.avg_sld, 5), 220.85 * 75 / 75) self.assertEqual(PriceParser.display(self.position.total_bot), 220.45 * 100 + 220.35 * 50) self.assertEqual(PriceParser.display(self.position.total_sld), 220.85 * 75) self.assertEqual(PriceParser.display(self.position.net_total), (220.85 * 75) - (220.45 * 100 + 220.35 * 50)) self.assertEqual(PriceParser.display(self.position.total_commission), 3.37) self.assertEqual(PriceParser.display(self.position.net_incl_comm), ((220.85 * 75) - (220.45 * 100 + 220.35 * 50)) - 3.37) self.assertEqual(PriceParser.display(self.position.avg_price, 5), (220.45 * 100 + 220.35 * 50 + 2.00) / 150 / 1) self.assertEqual(PriceParser.display(self.position.cost_basis), ((220.45 * 100 + 220.35 * 50 + 2.00) / 150) * 75) self.assertEqual(PriceParser.display(self.position.market_value), round(((220.85 + 220.86) / 2 * 75 * 1), 2)) self.assertEqual( PriceParser.display(self.position.unrealised_pnl), round(((220.85 + 220.86) / 2 * 75 * 1) - ((220.45 * 100 + 220.35 * 50 + 2.00) / 150) * 75, 2)) self.assertEqual( PriceParser.display(self.position.realised_pnl), (220.85 * 75) - ((220.45 * 100 + 220.35 * 50 + 2.00) / 150) * 75 - 1.37) print( "Sell 75 shares from current position at 221.24 with 1.37 commission. Market at 221.24/221.25:" ) self.position.transact_shares("SLD", 75, PriceParser.parse(221.24), PriceParser.parse(1.37)) self.position.update_market_value(PriceParser.parse(221.24), PriceParser.parse(221.25), datetime(2016, 1, 3)) print(self.position, '\n') self.assertEqual(self.position.buys, 150) self.assertEqual(self.position.sells, 150) self.assertEqual(self.position.net, 0) self.assertEqual(PriceParser.display(self.position.avg_bot, 5), round((220.45 * 100 + 220.35 * 50) / 150, 5)) self.assertEqual(PriceParser.display(self.position.avg_sld, 5), (220.85 * 75 + 221.24 * 75) / 150) self.assertEqual(PriceParser.display(self.position.total_bot), 220.45 * 100 + 220.35 * 50) self.assertEqual(PriceParser.display(self.position.total_sld), 220.85 * 75 + 221.24 * 75) self.assertEqual(PriceParser.display(self.position.net_total), (220.85 * 75 + 221.24 * 75) - (220.45 * 100 + 220.35 * 50)) self.assertEqual(PriceParser.display(self.position.total_commission), 3.37 + 1.37) self.assertEqual( PriceParser.display(self.position.net_incl_comm), round(((220.85 * 75 + 221.24 * 75) - (220.45 * 100 + 220.35 * 50)) - 3.37 - 1.37, 2)) self.assertEqual(PriceParser.display(self.position.avg_price, 5), (220.45 * 100 + 220.35 * 50 + 2.00) / 150 / 1) self.assertEqual(PriceParser.display(self.position.cost_basis), 0) self.assertEqual(PriceParser.display(self.position.market_value), 0) self.assertEqual(PriceParser.display(self.position.unrealised_pnl), 0) self.assertEqual( PriceParser.display(self.position.realised_pnl), round((220.85 * 75) - ((220.45 * 100 + 220.35 * 50 + 2.00) / 150) * 75 - 1.37 + (221.24 * 75) - ((220.45 * 100 + 220.35 * 50 + 2.00) / 150) * 75 - 1.37, 2))
def run(config, testing, tickers, filename, n, n_window): # Set up variables needed for backtest events_queue = queue.Queue() csv_dir = config.CSV_DATA_DIR initial_equity = PriceParser.parse(500000.00) d_tickers = OrderedDict() for ticker in tickers: ticker_path = os.path.join(csv_dir, "%s.csv" % ticker) df = pd.io.parsers.read_csv(ticker_path, header=0, parse_dates=True, dayfirst=True, index_col=1, names=("Ticker", "Time", "Bid", "Ask")) del df["Ticker"] d_tickers[ticker] = df if len(tickers) == 1: ticker = tickers[0] data = d_tickers[ticker] else: data = pd.Panel.from_dict(d_tickers) data = data.transpose(2, 1, 0) print(data) print("Null:") print(data.isnull().sum()) # Use Generic Tick Handler with Pandas Tick Iterator price_event_iterator = PandasTickEventIterator(data, tickers[0]) price_handler = GenericPriceHandler(events_queue, price_event_iterator) # Use the Display Strategy and ExampleStrategy strategy1 = DisplayStrategy(n=n, n_window=n_window) strategy2 = ExampleStrategy(tickers, events_queue) strategy = Strategies(strategy1, strategy2) # strategy = ExampleStrategy(tickers, events_queue) # Use an example Position Sizer position_sizer = FixedPositionSizer() # Use an example Risk Manager risk_manager = ExampleRiskManager() # Use the default Portfolio Handler portfolio_handler = PortfolioHandler(initial_equity, events_queue, price_handler, position_sizer, risk_manager) # Use the ExampleCompliance component compliance = ExampleCompliance(config) # Use a simulated IB Execution Handler execution_handler = IBSimulatedExecutionHandler(events_queue, price_handler, compliance) # Use the default Statistics statistics = SimpleStatistics(config, portfolio_handler) # Set up the backtest backtest = Backtest(price_handler, strategy, portfolio_handler, execution_handler, position_sizer, risk_manager, statistics, initial_equity) results = backtest.simulate_trading(testing=testing) statistics.save(filename) return results