Skip to content

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.

1
2
3
4
5
6
7
8
# 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:

1
2
3
4
5
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.