Strategies
Last updated
Last updated
Strategies allow you to automate (or partially automate) the buying and selling of instruments. The strategy APIs build upon the study classes and interfaces described in the preceding sections.
Let’s start buy looking at what is needed in the StudyHeader to declare a strategy:
The most important property to have set is “strategy=true”. The “autoEntry” and “manualEntry” properties may be used to indicate that the strategy is automatic or manual (Note: Trade Manager is an example of a manual entry strategy).
There are a number of other methods available on the Study class that may be used for strategies. The following excerpt from the Study class illustrates the strategy event methods:
onActivate(OrderContext ctx) – This method is called when the user presses the ‘Activate’ button in the Control Box. If the user has chosen the ‘Enter on Activate’ option this method should create an entry order for the appropriate direction.
onBarOpen(OrderContext ctx) – This method is called when the price bar is first opened. Note: live bar updates must be enabled for this method to be called.
onBarUpdate(OrderContext ctx) – This method is called when the current price bar is updated. Note: live bar updates must be enabled for this method to be called.
onBarClose(OrderContext ctx) – This method is called when the current price bar is closed (just before the next price bar is opened).
onSignal(OrderContext ctx, Object signal) – This method is called when a signal is raised by a study. This is a convenient method to override if your strategy is based on signals from an existing study (see Sample MA Cross Strategy).
onDeactivate(OrderContext ctx) – Called when the user presses the ‘Deactivate’ button. By default this method will close the open position (if enabled by the user).
onReset(OrderContext ctx) – This is called when the user presses the ‘reset’ button on the control box.
onPositionClosed(OrderContext ctx) – Called when an open position is closed.
onEnterNow(OrderContext ctx) – Called when the user presses the ‘Enter Now’ button on the Control Box. Note: this is only applicable for manual strategies.
In addition to the events described above, there are also a set of methods for handling orders and a set of properties available to strategies. For a full list of available methods, please consult the API documentation.
The OrderContext interface is passed to most of the strategy events and provides functionality for managing orders and positions. This interface also manages the current position state for the strategy and provides methods for getting the unrealized profit/loss, average entry price etc. A number of convenience methods also exist such as:
buy(int qty) – places a market order to buy the given quantity and waits for the order to be filled.
sell(int qty) – places a market order to sell the given quantity and waits for the order to be filled.
closeAtMarket() – closes the current position at market price.
The following methods may be used to manually create and manage stop, limit and market orders:
Strategies that simply buy and sell positions using the buy/sell methods will not have to deal with orders directly.
Market Orders vs Stop/Limit Orders
It can be very tempting to use stop and/or limit orders in place of market orders when implementing a strategy since these types of orders are already placed at the exchange and they can help guarantee execution at a particular price.
There are however several behaviors to be aware of when using these types of orders especially with fully automated strategies:
Limit Orders are not guaranteed to be executed. Even if the price action has traded through your limit price, it may not have been executed in a live environment if there was not enough demand to fill your order at the specified price.
Stop Orders are often triggered on Bid/Ask. It’s a common misconception that stop orders are triggered by last price. Most (if not all) brokers trigger stop orders using the bid or ask price (depending on whether it’s a buy or sell). This can cause your stop order to be executed unexpectedly early especially if there is a significant spread in the bid/ask prices.
Stop Orders are filled at market. Once a stop order is triggered, it is filled at market price. Stop Limit orders do exist, but are not currently supported by this API. Also note that not all brokers support Stop Limit orders.
If you choose to implement a fully automated strategy using non-market orders, you will need to consider these behaviors and add the appropriate code to handle cases where your orders do not get filled, or do not get filled at your expected price.
Ultimately, the choice you make will be a trade-off between order executions vs. fill price.
The following diagram illustrates some of the methods available in the Order interface. For a full list of methods, consult the API documentation.
Version 1.1 of the SDK introduces the ability for the user to define trading sessions for a strategy.
A ‘trading session’ is simply a valid time period during the day in which trading is allowed for the strategy. By default, all strategies support up to 2 trading sessions. This behavior can be modified in the StudyHeader:
The following screen shot illustrates an example of the MA Cross Strategy with the default settings for Trading Sessions.
The following additional methods have been added to the Settings class to access information chosen by the user at runtime within the strategy:
The following methods are also available on the Study class that may be optionally overridden. Note: if ‘enter on session start’ is enabled the strategy must override and implement the onSessionStart(...) method to implement the entry logic.
The following example illustrates a simple strategy based on the SampleMACross study (see sample project and signals in Section 6). This strategy will buy when the fast moving average crosses above the slow moving average and sell when it crosses below.
For convenience, this strategy will subclass the SampleMACross study and rely on the signals generated for ‘Fast MA Crossed Above’ (Signals.CROSS_ABOVE) and ‘Fast MA Crossed Below’ (Signals.CROSS_BELOW).
Let’s take a look at the StudyHeader. The key properties to note here are: strategy=true and autoEntry=true (1 below).
For this strategy, we are going to override two methods:
onActivate(OrderContext ctx) – If the user chooses to open a position on activate (see Trading Options panel), we will open a long or short position depending on whether the fast MA is above or below the slow MA (see 2 below)
onSignal(OrderContext ctx, Object signal) – In this method, we will use the signals generated in the SampleMACross class under the keys: Signals.CROSS_ABOVE and Signals.CROSS_BELOW (see calculate method). Note: we are reversing a position if it is open. IE: a long position becomes a short position and vice versa. (3 & 4 below)
A strategy can be in one of three different states (defined in Enums.StrategyState):
Inactive – No trades are active and the strategy will not place any trades.
Active – The strategy may place trades to open or close positions
Dormant – In this state, the strategy is still active but does not place any new trades
The current state of the strategy can be queried/set from the following methods (on the Study Class):
getState() – returns the current state of the strategy
setState(Enums.StrategyState state) – Sets the new state for the strategy.
In most cases, the strategy state is initiated by the user by pressing the ‘Activate’ or ‘Deactivate’ button from the Strategy Control Box. However, you can set the state from your strategy. This is most common when switching the strategy to the ‘Dormant’ state. You may want to use this state to indicate that the strategy is waiting for a specify condition to happen before placing trades again. This is often used when you just want the strategy to be active during specific hours of the day.
The following diagram illustrates these states and the transitions between them:
MotiveWave™ allows you to create strategies that respond to user input to enter or exit a position. This can be very useful as a way to help direct and manage exit points for user initiated trades. For an example of how this works, see the Trade Manager strategy.
The following screen shots illustrate the Trade Manager strategy in action:
In order to manage the orders for manual strategies, entry states have been defined to indicate the current stage the strategy is in. These states are defined in the Enums.EntryState enumeration.
None – No entry state, waiting for the user to initiate the entry process
Pre-Entry – The user has initiated the entry process and the strategy is preparing to create the entry order(s).
Waiting Entry – Waiting for entry orders to be filled (this state can be skipped if using market orders).
Open – Position is open, waiting for the position to be closed.
These states can be queried/set from the following methods in the Study Class:
getEntryState() – returns the current entry state for the strategy.
setEntryState(Enums.EntryState state) – sets the entry state for the strategy.
The following diagram illustrates these states and their transitions: