Important Points on Automated Trading¶
Live trading gotchas¶
Algorithmic trading can be advantageous as machines are faster than humans. But they are faster when things go wrong as well. It is of utmost importance that we take proper steps to make our strategies fault-tolerant. Below is a (non-exhaustive) set of points to keep in mind before you take your strategy live.
Good practices to follow
Strategy is designed to be fault-tolerant for corrupt input data
At the base level, check if the data you have received is very much different from last datapoints your strategy had. Most exchanges usually follow a market volatility control mechanism for publicly traded securities. These limits stock price movements and also enforce cool-off periods in such circumstances. If your algo received some extreme data points, it is highly likely they are wrong. Even if they are true, the market volatility control mechanism probably has already been triggered. If your strategy is not particularly designed to exploit these situations, it is a good practice to pause any trading activity till saner data arrive.
Strategy has necessary risk controls in place
This is, again, is an absolute must. At the minimum, it should control the max number of orders it can send (to control machine gunning), the max size of each order (machines do fat fingers too) and a kill switch (a percentage loss below which it should stop automatically). Blueshift® has all these features, and then some more. You can put controls based on the maximum position size, maximum leverage or even declare a white-list (black-list) of assets that the algo can (cannot) trade.
Checking/ cancelling pending open order before placing new orders
This one is an absolute must for live trading. A best practice is
usually to cancel all open orders before placing fresh orders, or,
updating the existing orders as per the algo signals. Else it is
easy to end up with a machine gun order scenario - the algo firing
up and queuing up orders faster than they can be processed. See the
code snippet below. We use the get_open_orders
and cancel_order
API functions to handle pending orders, before placing fresh
orders.
# get the pending open orders
open_orders = get_open_orders()
# cancel all open orders
for order_id in open_orders:
cancel_order(order_id)
# place fresh orders
for asset in context.universe:
order_target_percent(asset, target_percent)
Order placing and signal generations are isolated into specific functions
A strategy that places orders from multiple functions can mess up really fast. Make sure all your orders are placed only through a specific function. In such a design, chances of unforeseen mis-behaviours are considerably less.
Strategy is not over-sensitive to latency
Orders will be sent and processed over regular internet. So any latency sensitive strategies (like cross exchange arbitrage or market-making) are bound to suffer. Also internet connections are prone to interruptions or even complete outages. The strategy should be robust to such scenarios.
What to avoid
A strategy generating orders at a very high rate
These are more prone to instability, and also perhaps lose more in round trip trading costs than they make. A hair-trigger signal generation method may result in such a scenario. So make sure your signal generation is robust and expected holding periods are consistent with points above.
A strategy that triggers orders continuously for the same prevailing condition
If you are trading based on some technical indicators, say RSI
,
you usually want to place an order when the indicator crosses a
threshold (a change of state). The intention is not to generate
orders constantly as long as the indicator stays below (or over)
that threshold (a state). If you are using a state-based signal,
make sure the order functions are targeting in nature (e.g. the
ubiquitous order_target_percent
), not absolute (e.g. order
).
In case you are using absolute orders, make sure your signal
generation is based on change of state, not the state itself. For
example see below:
price = data.history(context.asset, 'close','200','1d')
rsi = talib.RSI(price.values, timeperiod=lookback)
# wrong: this will continuously place order as long as RSI below 30
if rsi[-1] < 30:
order(context.security, quantity)
A strategy trading close to the account capacity
Margin calls can put an automated strategy out of gear. Always ensure the account is funded adequately, so that the algo runs in an expected way.
Risk management and monitoring¶
Risk management and monitoring makes all the difference between blowing out the bank roll and making handsome profit. The above points will take care of some aspects of risk management, especially in automated trading set-up. But bank-roll management, position sizing etc, are still some points that need to be deliberated carefully before taking a strategy live. Also it is absolutely necessary we keep a close watch on the algo performance.
Live trading dashboard
At present Blueshift® only provides strategy updates on the web app. We plan to integrate other notifications (e-mails, texts) soon.