Skip to content
This repository has been archived by the owner on Nov 13, 2023. It is now read-only.

Commit

Permalink
Emit an event when an order gets submitted.
Browse files Browse the repository at this point in the history
  • Loading branch information
gbeced committed Jul 30, 2016
1 parent 5989252 commit 7becbdb
Show file tree
Hide file tree
Showing 9 changed files with 78 additions and 62 deletions.
9 changes: 5 additions & 4 deletions pyalgotrade/broker/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -460,10 +460,11 @@ def getDateTime(self):

class OrderEvent(object):
class Type:
ACCEPTED = 1 # Order has been acknowledged by the broker.
CANCELED = 2 # Order has been canceled.
PARTIALLY_FILLED = 3 # Order has been partially filled.
FILLED = 4 # Order has been completely filled.
SUBMITTED = 1 # Order has been submitted.
ACCEPTED = 2 # Order has been acknowledged by the broker.
CANCELED = 3 # Order has been canceled.
PARTIALLY_FILLED = 4 # Order has been partially filled.
FILLED = 5 # Order has been completely filled.

def __init__(self, order, eventyType, eventInfo):
self.__order = order
Expand Down
3 changes: 1 addition & 2 deletions pyalgotrade/broker/backtesting.py
Original file line number Diff line number Diff line change
Expand Up @@ -371,9 +371,8 @@ def submitOrder(self, order):
order.setSubmitted(self._getNextOrderId(), self._getCurrentDateTime())
self._registerOrder(order)
# Switch from INITIAL -> SUBMITTED
# IMPORTANT: Do not emit an event for this switch because when using the position interface
# the order is not yet mapped to the position and Position.onOrderUpdated will get called.
order.switchState(broker.Order.State.SUBMITTED)
self.notifyOrderEvent(broker.OrderEvent(order, broker.OrderEvent.Type.SUBMITTED, None))
else:
raise Exception("The order was already processed")

Expand Down
4 changes: 3 additions & 1 deletion pyalgotrade/strategy/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -484,8 +484,10 @@ def __onIdle(self):

def __onOrderEvent(self, broker_, orderEvent):
order = orderEvent.getOrder()
pos = self.__orderToPosition.get(order.getId(), None)
self.onOrderUpdated(order)

# Notify the position about the order event.
pos = self.__orderToPosition.get(order.getId(), None)
if pos is not None:
# Unlink the order from the position if its not active anymore.
if not order.isActive():
Expand Down
77 changes: 41 additions & 36 deletions testcases/broker_backtesting_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -198,8 +198,9 @@ def onOrderEvent(broker_, orderEvent):
def testRegressionGetActiveOrders(self):
activeOrders = []

def onOrderEvent(broker, orderEvent):
activeOrders.append(len(broker.getActiveOrders()))
def onOrderEvent(brk, orderEvent):
if orderEvent.getEventType() != broker.OrderEvent.Type.SUBMITTED:
activeOrders.append(len(brk.getActiveOrders()))

barFeed = self.buildBarFeed(BaseTestCase.TestInstrument, bar.Frequency.MINUTE)
brk = self.buildBroker(1000, barFeed)
Expand Down Expand Up @@ -308,20 +309,23 @@ def testSkipOrderSubmittedDuringEvent(self):
ordersUpdated = []

def onOrderEvent(broker_, orderEvent):
ordersUpdated.append(orderEvent.getOrder())
newOrder = brk.createMarketOrder(broker.Order.Action.BUY, BaseTestCase.TestInstrument, 1)
self.assertEquals(newOrder.getSubmitDateTime(), None)
brk.submitOrder(newOrder)
self.assertEquals(newOrder.getSubmitDateTime(), barFeed.getCurrentDateTime())
if orderEvent.getEventType() != broker.OrderEvent.Type.SUBMITTED:
ordersUpdated.append(orderEvent.getOrder())
newOrder = brk.createMarketOrder(broker.Order.Action.BUY, BaseTestCase.TestInstrument, 1)
self.assertEquals(newOrder.getSubmitDateTime(), None)
brk.submitOrder(newOrder)
self.assertEquals(newOrder.getSubmitDateTime(), barFeed.getCurrentDateTime())

brk.getOrderUpdatedEvent().subscribe(onOrderEvent)

# The first order gets submitted.
firstOrder = brk.createLimitOrder(broker.Order.Action.BUY, BaseTestCase.TestInstrument, 2, 1)
self.assertEquals(firstOrder.getSubmitDateTime(), None)
brk.submitOrder(firstOrder)
self.assertEquals(firstOrder.getSubmitDateTime(), barFeed.getCurrentDateTime())
self.assertEquals(len(ordersUpdated), 0)

# The first order gets accepted, and the second one gets submitted..
barFeed.dispatchBars(10, 15, 8, 12)
self.assertEquals(len(ordersUpdated), 1) # First order got accepted.
self.assertTrue(firstOrder in ordersUpdated)
Expand Down Expand Up @@ -357,10 +361,11 @@ def testPartialFillAndCancel(self):
self.assertEqual(order.getExecutionInfo().getPrice(), 12)
self.assertEqual(order.getExecutionInfo().getQuantity(), 2)
self.assertEqual(order.getExecutionInfo().getCommission(), 0)
self.assertEqual(len(cb.events), 3)
self.assertEqual(cb.events[0].getEventType(), broker.OrderEvent.Type.ACCEPTED)
self.assertEqual(cb.events[1].getEventType(), broker.OrderEvent.Type.PARTIALLY_FILLED)
self.assertEqual(cb.events[2].getEventType(), broker.OrderEvent.Type.CANCELED)
self.assertEqual(len(cb.events), 4)
self.assertEqual(cb.events[0].getEventType(), broker.OrderEvent.Type.SUBMITTED)
self.assertEqual(cb.events[1].getEventType(), broker.OrderEvent.Type.ACCEPTED)
self.assertEqual(cb.events[2].getEventType(), broker.OrderEvent.Type.PARTIALLY_FILLED)
self.assertEqual(cb.events[3].getEventType(), broker.OrderEvent.Type.CANCELED)

def testVolumeLimitPerBar1(self):
barFeed = self.buildBarFeed(BaseTestCase.TestInstrument, bar.Frequency.MINUTE)
Expand Down Expand Up @@ -644,7 +649,7 @@ def testBuyAndSell(self):
self.assertTrue(len(brk.getActiveOrders()) == 0)
self.assertTrue(brk.getCash() == 1)
self.assertTrue(brk.getShares(BaseTestCase.TestInstrument) == 1)
self.assertTrue(cb.eventCount == 2)
self.assertEqual(cb.eventCount, 3)
self.assertEqual(order.getFilled(), 1)
self.assertEqual(order.getRemaining(), 0)

Expand All @@ -664,7 +669,7 @@ def testBuyAndSell(self):
self.assertTrue(len(brk.getActiveOrders()) == 0)
self.assertTrue(brk.getCash() == 11)
self.assertTrue(brk.getShares(BaseTestCase.TestInstrument) == 0)
self.assertTrue(cb.eventCount == 2)
self.assertEqual(cb.eventCount, 3)
self.assertEqual(order.getFilled(), 1)
self.assertEqual(order.getRemaining(), 0)

Expand All @@ -688,7 +693,7 @@ def testFailToBuy(self):
self.assertTrue(len(brk.getActiveOrders()) == 1)
self.assertTrue(brk.getCash() == 5)
self.assertTrue(brk.getShares(BaseTestCase.TestInstrument) == 0)
self.assertTrue(cb.eventCount == 1)
self.assertEqual(cb.eventCount, 2)
self.assertEqual(order.getFilled(), 0)
self.assertEqual(order.getRemaining(), 1)

Expand Down Expand Up @@ -727,7 +732,7 @@ def testBuy_GTC(self):
self.assertTrue(len(brk.getActiveOrders()) == 1)
self.assertTrue(brk.getCash() == 5)
self.assertTrue(brk.getShares(BaseTestCase.TestInstrument) == 0)
self.assertTrue(cb.eventCount == 1)
self.assertEqual(cb.eventCount, 2)
self.assertEqual(order.getFilled(), 0)
self.assertEqual(order.getRemaining(), 1)

Expand Down Expand Up @@ -1270,7 +1275,7 @@ def testBuyAndSell_HitTargetPrice(self):
self.assertTrue(len(brk.getActiveOrders()) == 0)
self.assertTrue(brk.getCash() == 10)
self.assertTrue(brk.getShares(BaseTestCase.TestInstrument) == 1)
self.assertTrue(cb.eventCount == 2)
self.assertEqual(cb.eventCount, 3)

# Sell
cb = OrderUpdateCallback(brk)
Expand All @@ -1290,7 +1295,7 @@ def testBuyAndSell_HitTargetPrice(self):
self.assertTrue(len(brk.getActiveOrders()) == 0)
self.assertTrue(brk.getCash() == 25)
self.assertTrue(brk.getShares(BaseTestCase.TestInstrument) == 0)
self.assertTrue(cb.eventCount == 2)
self.assertEqual(cb.eventCount, 3)

def testBuyAndSell_GetBetterPrice(self):
barFeed = self.buildBarFeed(BaseTestCase.TestInstrument, bar.Frequency.MINUTE)
Expand All @@ -1314,7 +1319,7 @@ def testBuyAndSell_GetBetterPrice(self):
self.assertTrue(len(brk.getActiveOrders()) == 0)
self.assertTrue(brk.getCash() == 8)
self.assertTrue(brk.getShares(BaseTestCase.TestInstrument) == 1)
self.assertTrue(cb.eventCount == 2)
self.assertEqual(cb.eventCount, 3)

# Sell
cb = OrderUpdateCallback(brk)
Expand All @@ -1334,7 +1339,7 @@ def testBuyAndSell_GetBetterPrice(self):
self.assertTrue(len(brk.getActiveOrders()) == 0)
self.assertTrue(brk.getCash() == 24)
self.assertTrue(brk.getShares(BaseTestCase.TestInstrument) == 0)
self.assertTrue(cb.eventCount == 2)
self.assertEqual(cb.eventCount, 3)

def testBuyAndSell_GappingBars(self):
barFeed = self.buildBarFeed(BaseTestCase.TestInstrument, bar.Frequency.MINUTE)
Expand All @@ -1358,7 +1363,7 @@ def testBuyAndSell_GappingBars(self):
self.assertTrue(len(brk.getActiveOrders()) == 0)
self.assertTrue(brk.getCash() == 10)
self.assertTrue(brk.getShares(BaseTestCase.TestInstrument) == 1)
self.assertTrue(cb.eventCount == 2)
self.assertEqual(cb.eventCount, 3)

# Sell. Bar is above the target price.
cb = OrderUpdateCallback(brk)
Expand All @@ -1378,7 +1383,7 @@ def testBuyAndSell_GappingBars(self):
self.assertTrue(len(brk.getActiveOrders()) == 0)
self.assertTrue(brk.getCash() == 45)
self.assertTrue(brk.getShares(BaseTestCase.TestInstrument) == 0)
self.assertTrue(cb.eventCount == 2)
self.assertEqual(cb.eventCount, 3)

def testFailToBuy(self):
barFeed = self.buildBarFeed(BaseTestCase.TestInstrument, bar.Frequency.MINUTE)
Expand All @@ -1402,7 +1407,7 @@ def testFailToBuy(self):
self.assertTrue(len(brk.getActiveOrders()) == 1)
self.assertTrue(brk.getCash() == 5)
self.assertTrue(brk.getShares(BaseTestCase.TestInstrument) == 0)
self.assertTrue(cb.eventCount == 1)
self.assertEqual(cb.eventCount, 2)

# Fail to buy (couldn't get specific price). Canceled due to session close.
cb = OrderUpdateCallback(brk)
Expand Down Expand Up @@ -1441,7 +1446,7 @@ def testBuy_GTC(self):
self.assertTrue(len(brk.getActiveOrders()) == 1)
self.assertTrue(brk.getCash() == 10)
self.assertTrue(brk.getShares(BaseTestCase.TestInstrument) == 0)
self.assertTrue(cb.eventCount == 1)
self.assertEqual(cb.eventCount, 2)

# Buy
cb = OrderUpdateCallback(brk)
Expand All @@ -1454,7 +1459,7 @@ def testBuy_GTC(self):
self.assertTrue(len(brk.getActiveOrders()) == 0)
self.assertTrue(brk.getCash() == 6)
self.assertTrue(brk.getShares(BaseTestCase.TestInstrument) == 2)
self.assertTrue(cb.eventCount == 1)
self.assertEqual(cb.eventCount, 1)


class StopOrderTestCase(BaseTestCase):
Expand Down Expand Up @@ -1687,7 +1692,7 @@ def testLongPosStopLoss(self):
self.assertTrue(len(brk.getActiveOrders()) == 0)
self.assertTrue(brk.getCash() == 5)
self.assertTrue(brk.getShares(BaseTestCase.TestInstrument) == 1)
self.assertTrue(cb.eventCount == 2)
self.assertEqual(cb.eventCount, 3)

# Create stop loss order.
cb = OrderUpdateCallback(brk)
Expand All @@ -1704,7 +1709,7 @@ def testLongPosStopLoss(self):
self.assertTrue(len(brk.getActiveOrders()) == 1)
self.assertTrue(brk.getCash() == 5)
self.assertTrue(brk.getShares(BaseTestCase.TestInstrument) == 1)
self.assertTrue(cb.eventCount == 1)
self.assertEqual(cb.eventCount, 2)
barFeed.dispatchBars(10, 15, 8, 12) # Stop loss hit.
self.assertEqual(order.getFilled(), 1)
self.assertEqual(order.getRemaining(), 0)
Expand All @@ -1714,7 +1719,7 @@ def testLongPosStopLoss(self):
self.assertTrue(len(brk.getActiveOrders()) == 0)
self.assertTrue(brk.getCash() == 5+9)
self.assertTrue(brk.getShares(BaseTestCase.TestInstrument) == 0)
self.assertTrue(cb.eventCount == 2)
self.assertEqual(cb.eventCount, 3)

def testLongPosStopLoss_GappingBars(self):
barFeed = self.buildBarFeed(BaseTestCase.TestInstrument, bar.Frequency.MINUTE)
Expand All @@ -1738,7 +1743,7 @@ def testLongPosStopLoss_GappingBars(self):
self.assertTrue(len(brk.getActiveOrders()) == 0)
self.assertTrue(brk.getCash() == 5)
self.assertTrue(brk.getShares(BaseTestCase.TestInstrument) == 1)
self.assertTrue(cb.eventCount == 2)
self.assertEqual(cb.eventCount, 3)

# Create stop loss order.
cb = OrderUpdateCallback(brk)
Expand All @@ -1755,7 +1760,7 @@ def testLongPosStopLoss_GappingBars(self):
self.assertTrue(len(brk.getActiveOrders()) == 1)
self.assertTrue(brk.getCash() == 5)
self.assertTrue(brk.getShares(BaseTestCase.TestInstrument) == 1)
self.assertTrue(cb.eventCount == 1)
self.assertEqual(cb.eventCount, 2)
barFeed.dispatchBars(5, 8, 4, 7) # Stop loss hit.
self.assertTrue(order.isFilled())
self.assertEqual(order.getFilled(), 1)
Expand All @@ -1765,7 +1770,7 @@ def testLongPosStopLoss_GappingBars(self):
self.assertTrue(len(brk.getActiveOrders()) == 0)
self.assertTrue(brk.getCash() == 5+5) # Fill the stop loss order at open price.
self.assertTrue(brk.getShares(BaseTestCase.TestInstrument) == 0)
self.assertTrue(cb.eventCount == 2)
self.assertEqual(cb.eventCount, 3)

def testShortPosStopLoss(self):
barFeed = self.buildBarFeed(BaseTestCase.TestInstrument, bar.Frequency.MINUTE)
Expand All @@ -1789,7 +1794,7 @@ def testShortPosStopLoss(self):
self.assertTrue(len(brk.getActiveOrders()) == 0)
self.assertTrue(brk.getCash() == 15+10)
self.assertTrue(brk.getShares(BaseTestCase.TestInstrument) == -1)
self.assertTrue(cb.eventCount == 2)
self.assertEqual(cb.eventCount, 3)

# Create stop loss order.
cb = OrderUpdateCallback(brk)
Expand All @@ -1806,7 +1811,7 @@ def testShortPosStopLoss(self):
self.assertTrue(len(brk.getActiveOrders()) == 1)
self.assertTrue(brk.getCash() == 15+10)
self.assertTrue(brk.getShares(BaseTestCase.TestInstrument) == -1)
self.assertTrue(cb.eventCount == 1)
self.assertEqual(cb.eventCount, 2)
barFeed.dispatchBars(10, 15, 8, 12) # Stop loss hit.
self.assertTrue(order.isFilled())
self.assertEqual(order.getFilled(), 1)
Expand All @@ -1815,7 +1820,7 @@ def testShortPosStopLoss(self):
self.assertTrue(len(brk.getActiveOrders()) == 0)
self.assertTrue(brk.getCash() == 15-1)
self.assertTrue(brk.getShares(BaseTestCase.TestInstrument) == 0)
self.assertTrue(cb.eventCount == 2)
self.assertEqual(cb.eventCount, 3)

def testShortPosStopLoss_GappingBars(self):
barFeed = self.buildBarFeed(BaseTestCase.TestInstrument, bar.Frequency.MINUTE)
Expand All @@ -1839,7 +1844,7 @@ def testShortPosStopLoss_GappingBars(self):
self.assertTrue(len(brk.getActiveOrders()) == 0)
self.assertTrue(brk.getCash() == 15+10)
self.assertTrue(brk.getShares(BaseTestCase.TestInstrument) == -1)
self.assertTrue(cb.eventCount == 2)
self.assertEqual(cb.eventCount, 3)

# Create stop loss order.
cb = OrderUpdateCallback(brk)
Expand All @@ -1856,7 +1861,7 @@ def testShortPosStopLoss_GappingBars(self):
self.assertTrue(len(brk.getActiveOrders()) == 1)
self.assertTrue(brk.getCash() == 15+10)
self.assertTrue(brk.getShares(BaseTestCase.TestInstrument) == -1)
self.assertTrue(cb.eventCount == 1)
self.assertEqual(cb.eventCount, 2)
barFeed.dispatchBars(15, 20, 13, 14) # Stop loss hit.
self.assertTrue(order.isFilled())
self.assertEqual(order.getFilled(), 1)
Expand All @@ -1866,7 +1871,7 @@ def testShortPosStopLoss_GappingBars(self):
self.assertTrue(len(brk.getActiveOrders()) == 0)
self.assertTrue(brk.getCash() == 15-5)
self.assertTrue(brk.getShares(BaseTestCase.TestInstrument) == 0)
self.assertTrue(cb.eventCount == 2)
self.assertEqual(cb.eventCount, 3)


class StopLimitOrderTestCase(BaseTestCase):
Expand Down
9 changes: 9 additions & 0 deletions testcases/data/bccharts_example_2.output
Original file line number Diff line number Diff line change
@@ -1,27 +1,36 @@
2014-06-26 23:00:00 strategy [INFO] Buy 1.69 at 580.0
2014-06-26 23:00:00 strategy [INFO] Buy order 1 updated - Status: SUBMITTED - None
2014-06-26 23:30:00 strategy [INFO] Buy order 1 updated - Status: ACCEPTED - None
2014-06-26 23:30:00 strategy [INFO] Buy order 1 updated - Status: FILLED - 2014-06-26 23:30:00 - Price: 580.0 - Amount: 1.69 - Fee: 2.4505
2014-06-26 23:30:00 strategy [INFO] Buy 0.029 at 579.99
2014-06-26 23:30:00 strategy [INFO] Buy order 2 updated - Status: SUBMITTED - None
2014-06-27 00:00:00 strategy [INFO] Buy order 2 updated - Status: ACCEPTED - None
2014-06-27 00:00:00 strategy [INFO] Buy order 2 updated - Status: FILLED - 2014-06-27 00:00:00 - Price: 579.99 - Amount: 0.029 - Fee: 0.042049275
2014-07-03 18:30:00 strategy [INFO] Sell 1.719 at 639.0
2014-07-03 18:30:00 strategy [INFO] Sell order 3 updated - Status: SUBMITTED - None
2014-07-03 19:00:00 strategy [INFO] Sell order 3 updated - Status: ACCEPTED - None
2014-07-03 19:00:00 strategy [INFO] Sell order 3 updated - Status: FILLED - 2014-07-03 19:00:00 - Price: 639.0 - Amount: 1.719 - Fee: 2.7461025
2014-07-11 19:30:00 strategy [INFO] Buy 1.692 at 634.91
2014-07-11 19:30:00 strategy [INFO] Buy order 4 updated - Status: SUBMITTED - None
2014-07-11 20:00:00 strategy [INFO] Buy order 4 updated - Status: ACCEPTED - None
2014-07-11 20:00:00 strategy [INFO] Buy order 4 updated - Status: FILLED - 2014-07-11 20:00:00 - Price: 634.91 - Amount: 1.692 - Fee: 2.6856693
2014-07-11 20:30:00 strategy [INFO] Buy 0.03 at 634.99
2014-07-11 20:30:00 strategy [INFO] Buy order 5 updated - Status: SUBMITTED - None
2014-07-11 21:00:00 strategy [INFO] Buy order 5 updated - Status: ACCEPTED - None
2014-07-11 21:00:00 strategy [INFO] Buy order 5 updated - Status: FILLED - 2014-07-11 21:00:00 - Price: 634.99 - Amount: 0.03 - Fee: 0.04762425
2014-07-14 01:30:00 strategy [INFO] Sell 1.722 at 626.79
2014-07-14 01:30:00 strategy [INFO] Sell order 6 updated - Status: SUBMITTED - None
2014-07-14 02:00:00 strategy [INFO] Sell order 6 updated - Status: ACCEPTED - None
2014-07-14 02:00:00 strategy [INFO] Sell order 6 updated - Status: FILLED - 2014-07-14 02:00:00 - Price: 627.9 - Amount: 1.722 - Fee: 2.7031095
2014-07-31 14:00:00 strategy [INFO] Buy 1.81 at 584.13
2014-07-31 14:00:00 strategy [INFO] Buy order 7 updated - Status: SUBMITTED - None
2014-07-31 14:30:00 strategy [INFO] Buy order 7 updated - Status: ACCEPTED - None
2014-07-31 14:30:00 strategy [INFO] Buy order 7 updated - Status: FILLED - 2014-07-31 14:30:00 - Price: 584.1 - Amount: 1.81 - Fee: 2.6430525
2014-07-31 14:30:00 strategy [INFO] Buy 0.031 at 588.5
2014-07-31 14:30:00 strategy [INFO] Buy order 8 updated - Status: SUBMITTED - None
2014-07-31 15:00:00 strategy [INFO] Buy order 8 updated - Status: ACCEPTED - None
2014-07-31 15:00:00 strategy [INFO] Buy order 8 updated - Status: FILLED - 2014-07-31 15:00:00 - Price: 588.5 - Amount: 0.031 - Fee: 0.04560875
2014-08-03 00:00:00 strategy [INFO] Sell 1.841 at 587.64
2014-08-03 00:00:00 strategy [INFO] Sell order 9 updated - Status: SUBMITTED - None
2014-08-03 00:30:00 strategy [INFO] Sell order 9 updated - Status: ACCEPTED - None
2014-08-03 00:30:00 strategy [INFO] Sell order 9 updated - Status: FILLED - 2014-08-03 00:30:00 - Price: 589.59 - Amount: 1.841 - Fee: 2.713587975
2 changes: 1 addition & 1 deletion testcases/drawdown_analyzer_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ def __testIGE_BrokerImpl(self, quantity):
strat.run()

self.assertTrue(round(strat.getBroker().getCash(), 2) == initialCash + (127.64 - 42.09) * quantity)
self.assertEqual(strat.orderUpdatedCalls, 4)
self.assertEqual(strat.orderUpdatedCalls, 6)
self.assertTrue(round(stratAnalyzer.getMaxDrawDown(), 5) == 0.31178)
self.assertTrue(stratAnalyzer.getLongestDrawDownDuration() == datetime.timedelta(days=623))

Expand Down
Loading

0 comments on commit 7becbdb

Please sign in to comment.