Nothing is set in stone, and obviously this design is liable to change. I doubt the requirements themselves will change though.
Requirements:
- The API adapter must be able to execute:
market_order and limit_order operations for both BUY and SELL types.
- The API adapter should be able to determine whether an order is by quantity or price.
- Orders originating from the
Strategy must run through an authorisation guard that determines whether a transaction is allowed, and fill any parameters that are missing - i.e. perform risk mitigation.
- The API adapter must provide appropriate updates on the status of an order, and the resulting status of the account.
- The
SyncAgent must ensure that it maintains the correct state for this information.
- Metrics/observability should be available for all orders and subsequent updates.
Current Idea

Questions
Is the authorise call really mandatory?
- For most strategies which simply buy/sell one given asset, perhaps a simple flag could be used to skip the
authorise call - i.e. force=False.
- Alternatively the
authorise() call could no longer be an abstract method, and could simply verify that arguments are correct - i.e. if SELL then is there a corresponding position to actually sell?
Potential Gotchas
SyncAgent race conditions
All Orders are triggered via the BaseStrategy - specificaly the SyncAgent strategy - which means they run concurrently to the strategy; this may lead to odd race conditions or duplicate orders. Although the queue.Queue that's used to interact with the SyncAgent should ensure sequential operations, that still doesn't account for state changes between (a) the order being requested in the queue, and (b) the order being placed.
Potential Mitigation: This can't really be solved simply with locking, as order updates will be inbound/pending whilst the message is awaing processing. There must be a clearly defined and logical sequence of (a) checking the registry, (b) updating the registry, (c) calling authorise(...), and (d) making the transaction. The SyncAgent event loop must ensure that a given request has been acknowledged before continuing to process the next message.
Work Required:
Inspirations
Zipline has a really simple interface to execute orders - a method named order_asset([symbol], [qty]). This doesn't have the flexibility that the above design has, but it is certainly a requires a simpler - and therefore likely less error-prone - implementation.
QuantConnect supports six types of order, each via their own function. This is likely a far better and cuts down on the params in the TransactionRequest that the strategy needs to supply.
Additionally the API for making orders returns a "Ticket" object, allowing you to retrieve more information - the kind of information that the SyncAgent maintains.
ArcadeTrader actually has the strategy return an object determining whether a trade should be made; this is simpler, but really conflicts with the SyncAgent idea - and would require a few design changes.
Being able to associate a reason - i.e. a string describing the conditions which triggered the request - with a trade seems nice though.
Nothing is set in stone, and obviously this design is liable to change. I doubt the requirements themselves will change though.
Requirements:
market_orderandlimit_orderoperations for bothBUYandSELLtypes.Strategymust run through an authorisation guard that determines whether a transaction is allowed, and fill any parameters that are missing - i.e. perform risk mitigation.SyncAgentmust ensure that it maintains the correct state for this information.Current Idea
Questions
Is the
authorisecall really mandatory?authorisecall - i.e.force=False.authorise()call could no longer be an abstract method, and could simply verify that arguments are correct - i.e. if SELL then is there a corresponding position to actually sell?Potential Gotchas
SyncAgentrace conditionsAll Orders are triggered via the
BaseStrategy- specificaly theSyncAgentstrategy - which means they run concurrently to the strategy; this may lead to odd race conditions or duplicate orders. Although thequeue.Queuethat's used to interact with theSyncAgentshould ensure sequential operations, that still doesn't account for state changes between (a) the order being requested in the queue, and (b) the order being placed.Potential Mitigation: This can't really be solved simply with locking, as order updates will be inbound/pending whilst the message is awaing processing. There must be a clearly defined and logical sequence of (a) checking the registry, (b) updating the registry, (c) calling
authorise(...), and (d) making the transaction. TheSyncAgentevent loop must ensure that a given request has been acknowledged before continuing to process the next message.Work Required:
AccountStatusSyncAgentAdapters are expected to follow for allowing orders.True- to verify order validity prior to placing the order.Inspirations
quantopian/zipline
Zipline has a really simple interface to execute orders - a method named
order_asset([symbol], [qty]). This doesn't have the flexibility that the above design has, but it is certainly a requires a simpler - and therefore likely less error-prone - implementation.quantconnect
QuantConnect supports six types of order, each via their own function. This is likely a far better and cuts down on the params in the
TransactionRequestthat the strategy needs to supply.Additionally the API for making orders returns a "Ticket" object, allowing you to retrieve more information - the kind of information that the
SyncAgentmaintains.arcadetrader
ArcadeTrader actually has the strategy return an object determining whether a trade should be made; this is simpler, but really conflicts with the
SyncAgentidea - and would require a few design changes.Being able to associate a reason - i.e. a string describing the conditions which triggered the request - with a trade seems nice though.