def testSeparateAndCombined(self): posA = returns.PositionTracker(broker.IntegerTraits()) posA.buy(11, 10) posA.sell(11, 30) self.assertEqual(posA.getNetProfit(), 20 * 11) self.assertEqual(posA.getReturn(), 2) self.assertEqual(posA.getCostBasis(), 11 * 10) posB = returns.PositionTracker(broker.IntegerTraits()) posB.sell(100, 1.1) posB.buy(100, 1) self.assertEqual(round(posB.getNetProfit(), 2), 100 * 0.1) self.assertEqual(round(posB.getReturn(), 2), 0.09) self.assertEqual(posB.getCostBasis(), 100 * 1.1) combinedPos = returns.PositionTracker(broker.IntegerTraits()) combinedPos.buy(11, 10) combinedPos.sell(11, 30) self.assertEqual(combinedPos.getCostBasis(), 11 * 10) combinedPos.sell(100, 1.1) combinedPos.buy(100, 1) self.assertEqual(combinedPos.getCostBasis(), 100 * 1.1) self.assertEqual(round(combinedPos.getReturn(), 6), 2.090909) # The return of the combined position is less than the two returns combined # because when the second position gets opened the amount of cash not invested is greater # than that of posB alone. self.assertLess(round(combinedPos.getReturn(), 6), ((1 + posA.getReturn()) * (1 + posB.getReturn()) - 1))
def __createOrder(self, orderId, actionId, stateId, typeId, onClose, allOrNone, avgFillPrice, commissions, filled, gootTillCancelled, instrument, quantity, submitDateTime, stopLossValue, stopHit): action = Order.Action.fromInteger(actionId) state = Order.State.fromInteger(stateId) orderType = Order.Type.fromInteger(typeId) allOrNone = False if (allOrNone == 0 or allOrNone is None) else True filled = False if (filled == 0 or filled is None) else True gootTillCancelled = False if (gootTillCancelled == 0 or gootTillCancelled is None) else True stopHit = False if (stopHit == 0 or stopHit is None) else True if orderType == Order.Type.STOP: order = backtesting.StopOrder(action, instrument, stopLossValue, quantity, broker.IntegerTraits()) order.setStopHit(stopHit) elif orderType == Order.Type.MARKET: order = backtesting.MarketOrder(action, instrument, quantity, onClose, broker.IntegerTraits()) order.stopLossValue = stopLossValue else: raise ("Unsupported order type") order.setState(state) order.setAllOrNone(allOrNone) order.setAvgFillPrice(avgFillPrice) order.setCommissions(commissions) order.setFilled(filled) order.setGoodTillCanceled(gootTillCancelled) order.setSubmitted(orderId, submitDateTime) return order
def testBuyAndSellMultipleEvals(self): posTracker = returns.PositionTracker(broker.IntegerTraits()) posTracker.buy(2, 10) self.assertEqual(posTracker.getAvgPrice(), 10) self.assertEqual(posTracker.getPnL(), 0) self.assertEqual(posTracker.getPnL(price=9), -2) self.assertEqual(posTracker.getPnL(price=10), 0) self.assertEqual(posTracker.getPnL(price=11), 2) self.assertEqual(posTracker.getReturn(10), 0) self.assertEqual(posTracker.getPnL(price=11), 2) self.assertEqual(round(posTracker.getReturn(11), 2), 0.1) self.assertEqual(posTracker.getPnL(price=20), 20) self.assertEqual(posTracker.getReturn(20), 1) posTracker.sell(1, 11) self.assertEqual(posTracker.getAvgPrice(), 10) self.assertEqual(posTracker.getPnL(price=11), 2) self.assertEqual(posTracker.getReturn(11), 0.1) posTracker.sell(1, 10) self.assertEqual(posTracker.getAvgPrice(), 0) self.assertEqual(posTracker.getPnL(), 1) self.assertEqual(posTracker.getReturn(11), 0.05)
def testBuyAndSellMultipleEvals(self): posTracker = returns.PositionTracker(broker.IntegerTraits()) posTracker.buy(2, 10) self.assertEqual(posTracker.getCostPerShare(), 10) self.assertEqual(posTracker.getNetProfit(), 0) self.assertEqual(posTracker.getNetProfit(9), -2) self.assertEqual(posTracker.getNetProfit(10), 0) self.assertEqual(posTracker.getNetProfit(11), 2) self.assertEqual(posTracker.getReturn(10), 0) self.assertEqual(posTracker.getNetProfit(11), 2) self.assertEqual(round(posTracker.getReturn(11), 2), 0.1) self.assertEqual(posTracker.getNetProfit(20), 20) self.assertEqual(posTracker.getReturn(20), 1) posTracker.sell(1, 11) self.assertEqual(posTracker.getCostPerShare(), 10) self.assertEqual(posTracker.getNetProfit(11), 2) self.assertEqual(posTracker.getReturn(11), 0.1) posTracker.sell(1, 10) self.assertEqual(posTracker.getCostPerShare(), 0) self.assertEqual(posTracker.getNetProfit(), 1) self.assertEqual(posTracker.getReturn(11), 0.05)
def __test_impl(self, action): order = backtesting.MarketOrder(action, BaseTestCase.TestInstrument, 25, False, broker.IntegerTraits()) price = 10 volumeUsed = 0 # Try the order once. slippedPrice = self.slippage.calculatePrice( order, price, order.getQuantity(), self.barsBuilder.nextBar(10, 11, 9, 10, volume=100), volumeUsed) quantity = order.getQuantity() expectedPriceImpactPct = quantity / 100.0 * quantity / 100.0 * self.priceImpact self.assertEqual(expectedPriceImpactPct, 0.00625) if action == broker.Order.Action.BUY: self.assertEqual(slippedPrice, price * (1 + expectedPriceImpactPct)) else: self.assertEqual(slippedPrice, price * (1 - expectedPriceImpactPct)) # Try the same order once again. volumeUsed += quantity quantity += order.getQuantity() slippedPrice = self.slippage.calculatePrice( order, price, order.getQuantity(), self.barsBuilder.nextBar(10, 11, 9, 10, volume=100), volumeUsed) expectedPriceImpactPct = quantity / 100.0 * quantity / 100.0 * self.priceImpact self.assertEqual(expectedPriceImpactPct, 0.025) if action == broker.Order.Action.BUY: self.assertEqual(slippedPrice, price * (1 + expectedPriceImpactPct)) else: self.assertEqual(slippedPrice, price * (1 - expectedPriceImpactPct))
def testBuyAndSellWin(self): posTracker = returns.PositionTracker(broker.IntegerTraits()) posTracker.buy(1, 10) self.assertEqual(posTracker.getAvgPrice(), 10) posTracker.sell(1, 11) self.assertEqual(posTracker.getAvgPrice(), 0) self.assertEqual(posTracker.getPnL(), 1) self.assertTrue(posTracker.getReturn() == 0.1)
def testBuyAndSellWin(self): posTracker = returns.PositionTracker(broker.IntegerTraits()) posTracker.buy(1, 10) self.assertEqual(posTracker.getCostPerShare(), 10) posTracker.sell(1, 11) self.assertEqual(posTracker.getCostPerShare(), 0) self.assertEqual(posTracker.getNetProfit(), 1) self.assertTrue(posTracker.getReturn() == 0.1)
def testBuyAndSellBreakEvenWithCommision(self): posTracker = returns.PositionTracker(broker.IntegerTraits()) posTracker.buy(1, 10, 0.5) self.assertEqual(posTracker.getAvgPrice(), 10) posTracker.sell(1, 11, 0.5) self.assertEqual(posTracker.getPnL(includeCommissions=False), 1) self.assertEqual(posTracker.getPnL(), 0) self.assertEqual(posTracker.getReturn(includeCommissions=False), 0.1) self.assertEqual(posTracker.getReturn(), 0)
def __getFilledMarketOrder(self, quantity, price): order = backtesting.MarketOrder(broker.Order.Action.BUY, BaseTestCase.TestInstrument, quantity, False, broker.IntegerTraits()) order.setState(broker.Order.State.ACCEPTED) order.addExecutionInfo( broker.OrderExecutionInfo(price, quantity, 0, datetime.datetime.now())) return order
def testBuyAndSellBreakEven(self): posTracker = returns.PositionTracker(broker.IntegerTraits()) posTracker.buy(1, 10) self.assertEqual(posTracker.getAvgPrice(), 10) posTracker.sell(1, 10) # self.assertEqual(posTracker.getCash(), 0) self.assertEqual(posTracker.getAvgPrice(), 0) self.assertEqual(posTracker.getPnL(), 0) self.assertEqual(posTracker.getReturn(), 0)
def testSellAndBuyWin(self): posTracker = returns.PositionTracker(broker.IntegerTraits()) posTracker.sell(1, 13) self.assertEqual(posTracker.getAvgPrice(), 13) self.assertEqual(posTracker.getPnL(), 0) self.assertEqual(posTracker.getPnL(price=10), 3) posTracker.buy(1, 10) self.assertEqual(posTracker.getAvgPrice(), 0) self.assertEqual(posTracker.getPnL(), 3) self.assertEqual(round(posTracker.getReturn(), 9), round(0.23076923076923, 9))
def testBuyAndSellInTwoTrades(self): posTracker = returns.PositionTracker(broker.IntegerTraits()) posTracker.buy(2, 10) self.assertEqual(posTracker.getAvgPrice(), 10) posTracker.sell(1, 11) self.assertEqual(posTracker.getAvgPrice(), 10) self.assertEqual(posTracker.getPnL(), 1) self.assertEqual(posTracker.getReturn(), 0.05) posTracker.sell(1, 12) self.assertEqual(posTracker.getPnL(), 3) self.assertEqual(posTracker.getReturn(), 3 / 20.0)
def testSellAndBuyWin(self): posTracker = returns.PositionTracker(broker.IntegerTraits()) posTracker.sell(1, 13) self.assertEqual(posTracker.getCostPerShare(), 13) self.assertEqual(posTracker.getNetProfit(), 0) self.assertEqual(posTracker.getNetProfit(10), 3) posTracker.buy(1, 10) self.assertEqual(posTracker.getCostPerShare(), 0) self.assertEqual(posTracker.getNetProfit(), 3) self.assertEqual(round(posTracker.getReturn(), 9), round(0.23076923076923, 9))
def test_full_volume_used(self): orderSize = 100 order = backtesting.MarketOrder(broker.Order.Action.BUY, BaseTestCase.TestInstrument, orderSize, False, broker.IntegerTraits()) price = 10 volumeUsed = 0 # Try the order once. slippedPrice = self.slippage.calculatePrice( order, price, order.getQuantity(), self.barsBuilder.nextBar(10, 11, 9, 10, volume=orderSize), volumeUsed) self.assertEqual(slippedPrice, price * 1.1)
def __test_impl(self, action): order = backtesting.MarketOrder(action, BaseTestCase.TestInstrument, 5, False, broker.IntegerTraits()) price = 10 slippedPrice = self.slippage.calculatePrice( order, price, order.getQuantity(), self.barsBuilder.nextBar(10, 11, 9, 10, volume=100), 0) self.assertEqual(price, slippedPrice) slippedPrice = self.slippage.calculatePrice( order, price, order.getQuantity(), self.barsBuilder.nextBar(10, 11, 9, 10, volume=100), 20) self.assertEqual(slippedPrice, price)
def testBuyAndSellBreakEvenWithCommission(self): posTracker = returns.PositionTracker(broker.IntegerTraits()) # self.assertEqual(posTracker.getCash(), 0) posTracker.buy(1, 10, 0.01) # self.assertEqual(posTracker.getCash(), -10.01) self.assertEqual(posTracker.getAvgPrice(), 10) posTracker.sell(1, 10.02, 0.01) # self.assertEqual(round(posTracker.getCash(), 2), 0) self.assertEqual(posTracker.getAvgPrice(), 0) # We need to round to avoid floating point errors. # The same issue can be reproduced with this piece of code: # a = 10.02 - 10 # b = 0.02 # print a - b # print a - b == 0 self.assertEqual(posTracker.getPosition(), 0) self.assertEqual(round(posTracker.getPnL(), 2), 0) self.assertEqual(round(posTracker.getReturn(), 2), 0)
def testSellAndBuyMultipleEvals(self): posTracker = returns.PositionTracker(broker.IntegerTraits()) posTracker.sell(2, 11) self.assertEqual(posTracker.getAvgPrice(), 11) self.assertEqual(posTracker.getPnL(price=10), 2) self.assertEqual(posTracker.getPnL(price=11), 0) self.assertEqual(posTracker.getPnL(price=12), -2) self.assertEqual(posTracker.getReturn(11), 0) posTracker.buy(1, 10) self.assertEqual(posTracker.getAvgPrice(), 11) self.assertEqual(posTracker.getPnL(price=11), 1) self.assertEqual(round(posTracker.getReturn(11), 9), round(0.045454545, 9)) posTracker.buy(1, 10) self.assertEqual(posTracker.getAvgPrice(), 0) self.assertEqual(posTracker.getPnL(), 2) self.assertEqual(posTracker.getPnL(price=100), 2) self.assertEqual(round(posTracker.getReturn(), 9), round(0.090909091, 9))
def testSellBuySell(self): posTracker = returns.PositionTracker(broker.IntegerTraits()) posTracker.sell(1, 10) self.assertEqual(posTracker.getAvgPrice(), 10) self.assertEqual(posTracker.getPnL(), 0) self.assertEqual(posTracker.getReturn(), 0) self.assertEqual(posTracker.getPnL(price=13), -3) self.assertEqual(posTracker.getReturn(13), -0.3) # Closing the short position and going long 1 @ $13. # The cost basis for the new position is $13. posTracker.buy(2, 13) self.assertEqual(posTracker.getAvgPrice(), 13) self.assertEqual(posTracker.getPnL(), -3) self.assertEqual(round(posTracker.getReturn(), 9), round(-0.23076923076923, 9)) posTracker.sell(1, 10) self.assertEqual(posTracker.getAvgPrice(), 0) self.assertEqual(posTracker.getPnL(), -6) self.assertEqual(round(posTracker.getReturn(), 9), round(-0.46153846153846, 9))
def testSellAndBuyMultipleEvals(self): posTracker = returns.PositionTracker(broker.IntegerTraits()) posTracker.sell(2, 11) self.assertEqual(posTracker.getCostPerShare(), 11) self.assertEqual(posTracker.getNetProfit(10), 2) self.assertEqual(posTracker.getNetProfit(11), 0) self.assertEqual(posTracker.getNetProfit(12), -2) self.assertEqual(posTracker.getReturn(11), 0) posTracker.buy(1, 10) self.assertEqual(posTracker.getCostPerShare(), 11) self.assertEqual(posTracker.getNetProfit(11), 1) self.assertEqual(round(posTracker.getReturn(11), 9), round(0.045454545, 9)) posTracker.buy(1, 10) self.assertEqual(posTracker.getCostPerShare(), 0) self.assertEqual(posTracker.getNetProfit(), 2) self.assertEqual(posTracker.getNetProfit(100), 2) self.assertEqual(round(posTracker.getReturn(), 9), round(0.090909091, 9))
def testBuySellBuy(self): posTracker = returns.PositionTracker(broker.IntegerTraits()) posTracker.buy(1, 10) self.assertEqual(posTracker.getAvgPrice(), 10) self.assertEqual(posTracker.getPnL(price=9), -1) self.assertEqual(posTracker.getPnL(), 0) self.assertEqual(posTracker.getPnL(price=10), 0) self.assertEqual(posTracker.getPnL(price=11), 1) self.assertEqual(posTracker.getReturn(), 0) self.assertEqual(posTracker.getReturn(13), 0.3) # Closing the long position and short selling 1 @ $13. # The cost basis for the new position is $13. posTracker.sell(2, 13) self.assertEqual(posTracker.getAvgPrice(), 13) self.assertEqual(posTracker.getPnL(), 3) self.assertEqual(round(posTracker.getReturn(), 8), 0.23076923) posTracker.buy(1, 10) self.assertEqual(posTracker.getAvgPrice(), 0) self.assertEqual(posTracker.getPnL(), 6) self.assertEqual(round(posTracker.getReturn(), 9), round(0.46153846153846, 9))
def testProfitReturnsAndCost(self): posTracker = returns.PositionTracker(broker.IntegerTraits()) posTracker.buy(10, 1) self.assertEqual(posTracker.getPnL(), 0) self.assertEqual(posTracker.getAvgPrice(), 1) self.assertEqual(posTracker.getCommissions(), 0) # self.assertEqual(posTracker.getCash(), -10) posTracker.buy(20, 1, 10) self.assertEqual(posTracker.getPnL(), -10) self.assertEqual(posTracker.getAvgPrice(), 1) self.assertEqual(posTracker.getCommissions(), 10) # self.assertEqual(posTracker.getCash(), -40) posTracker.sell(30, 1) self.assertEqual(posTracker.getAvgPrice(), 0) self.assertEqual(posTracker.getPnL(), -10) # self.assertEqual(posTracker.getCash(), -10) self.assertEqual(posTracker.getCommissions(), 10) self.assertEqual(posTracker.getReturn(), -10 / 30.0) posTracker.buy(10, 1) self.assertEqual(posTracker.getPnL(), -10) self.assertEqual(posTracker.getAvgPrice(), 1)
def getInstrumentTraits(self, instrument): return broker.IntegerTraits()