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 __onOrderEvent(self, broker_, orderEvent): # Only interested in filled or partially filled orders. if orderEvent.getEventType() not in ( broker.OrderEvent.Type.PARTIALLY_FILLED, broker.OrderEvent.Type.FILLED): return order = orderEvent.getOrder() # Get or create the tracker for this instrument. try: posTracker = self.__posTrackers[order.getInstrument()] except KeyError: posTracker = returns.PositionTracker(order.getInstrumentTraits()) self.__posTrackers[order.getInstrument()] = posTracker # Update the tracker for this order. execInfo = orderEvent.getEventInfo() price = execInfo.getPrice() commission = execInfo.getCommission() action = order.getAction() if action in [ broker.Order.Action.BUY, broker.Order.Action.BUY_TO_COVER ]: quantity = execInfo.getQuantity() elif action in [ broker.Order.Action.SELL, broker.Order.Action.SELL_SHORT ]: quantity = execInfo.getQuantity() * -1 else: # Unknown action assert (False) self.__updatePosTracker(posTracker, price, commission, quantity)
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 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 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 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.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 testSeparateAndCombined(self): posA = returns.PositionTracker(broker.IntegerTraits()) posA.buy(11, 10) posA.sell(11, 30) self.assertEqual(posA.getPnL(), 20 * 11) self.assertEqual(posA.getReturn(), 2) posB = returns.PositionTracker(broker.IntegerTraits()) posB.sell(100, 1.1) posB.buy(100, 1) self.assertEqual(round(posB.getPnL(), 2), 100 * 0.1) self.assertEqual(round(posB.getReturn(), 2), 0.09) combinedPos = returns.PositionTracker(broker.IntegerTraits()) combinedPos.buy(11, 10) combinedPos.sell(11, 30) combinedPos.sell(100, 1.1) combinedPos.buy(100, 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 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 __init__(self, strategy, entryOrder, goodTillCanceled, allOrNone): # The order must be created but not submitted. assert (entryOrder.isInitial()) self.__state = None self.__activeOrders = {} self.__shares = 0 self.__strategy = strategy self.__entryOrder = None self.__entryDateTime = None self.__exitOrder = None self.__exitDateTime = None self.__posTracker = returns.PositionTracker( entryOrder.getInstrumentTraits()) self.__allOrNone = allOrNone self.switchState(WaitingEntryState()) entryOrder.setGoodTillCanceled(goodTillCanceled) entryOrder.setAllOrNone(allOrNone) self.__submitAndRegisterOrder(entryOrder) self.__entryOrder = entryOrder
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 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)