Extending the AutoTrade Example Platform
This is part two of a three part article series. In the first article, Introducing Tradovate AutoTrade, we discussed how to acquire the necessary resources to run the AutoTrade framework, we reviewed the basic layout of the platform, and we learned how to run the example project. In this article we will go into detail about extending the robot.
The Tradovate REST API has an enormous amount of functionality and flexibility — however this affects the rate at which one can learn and master the API. AutoTrade is intended to be a usable example that helps flatten the learning curve a bit, offering boilerplate code for communicating with the API as well as a high-level interface for writing your own automated strategies.
We’ve already gone over the basics of catching events from the Tradovate API using the Strategy
class’ next
function, using function extraction to separate our logic into readable units. I also hinted at the functional-paradigmatic nature of the next
function’s implementation. Let’s talk more about that.
If we were to look at the pre-built CrossoverStrategy
implementation, we’d see that each of the extracted event handler functions (that is onChart
, onProps
, etc.) each return an object with at least a state
field, but optionally an effects
field as well. Below is CrossoverStrategy
's onUserSync
handler, it catches TdEvent.UserSync
events and produces a new state based on the data
and props
parameters. Typically UserSync
happens once — right after the socket connects to the server. We can use it to find our existing positions, or other data related to your particular user. Pay close attention to the return object, which utilizes both the state
and optional effects
fields:
All this code really says is that if you already have a position in the chosen contract at startup, add it and its product data as the position
and product
fields of the state
object, respectively. Specifically the shape of the return object of any of the next
function’s event handlers should match this interface:
In the declarations above, EventEffect
is a type that describes the shape of how we declare individual side effects in the return of our next
function and its event handlers. EventHandlerResult
describes the full shape of next
function results, which must include a state
field that can be any plain object, and an effects
field which must be an array of EventEffect
shaped objects.
Peeking back at the example from CrossoverStrategy
, take note of how we use the spread operator ( ...
) with prevState
to keep any previous state that this particular handler doesn’t touch. If any of my readers are familiar with the extremely popular Redux library, you might recognize our functional approach as being quite similar. next
is our reducer function, which delegates sub-functionality to the event handlers (such as onUserSync
). Each dispatch
call changes the robot’s underlying model which we can consider to be like the state store in Redux. Finally, just like with Redux, we can add in custom middleware to handle impure code (or code which causes side effects).
Now that we’ve reviewed Strategy
's next
function in greater depth, let’s begin writing our own event handlers. We’ll design a very basic strategy that intercepts the TdEvent.Chart
event type to store and display current price for the chosen contract. We will store the close
field from each bar and draw to our console using a custom side effect. Open up the AutoTrade repo in VSCode and find the priceDisplayStrategy.js
file. It should look like this:
Our initial state contains only one field — a special field called buffer
. buffer
is an instance of the DataBuffer
class, which is a tool to help us collect and transform the raw data we receive from the WebSocket. When we call the buffer’s concat
method, you will get a brand new buffer with the appropriate data added onto the original buffer’s data. When we use Chart event data, it is necessary to return the updated buffer in the state (which you’ll see in the embedded code below). This keeps the buffer’s data set immutable.
Now that we have some initial state, let’s add some code to the next
function.
As described in the last article, we can use a switch statement to differentiate between the actions taken based on the event captured. In our case, we only care about Chart events, so we simply default
everything else.
This is pretty much all the pure code we need for this ‘strategy’ (it will never place orders so it’s hard to call it a real strategy). We still do need side effects for drawing to the console, however. Let’s explore how to create and register a custom side effect for your strategy. Look at the return of the TdEvent.Chart
case:
Notice how we have to declare state
as a field. This is to make room for the other possible field we talked about, effects
. Let’s add one to this return statement.
We can give our events any string name, but I like using a URL-like naming scheme. Now to react to this event we need to write a handler function. Create a new file, drawPrice.js
. In this file, we’re going to write our first middleware (or side-effecting function). Each middleware is a transformation on the action sent. They follow this signature:
(State, Action) => Action
Each effect must accept the last state and an action as parameters, returning a new action (or the same action). The following drawPriceEffect
is very simple. It utilizes a built-in method drawToConsole
to draw the current price, which we get from buffer.last()
.
That’s all good, but in order to use it we need to register it to our Strategy subclass. That’s easy though. Go look at init
for the DisplayPriceStrategy
subclass. Add the following:
Now our middleware will be called when the dispatcher fires, making its action-transformation before the event handlers run. What this allows for are operations on the actions that are dispatched, so that we can do fancy things like split a try action into success and fail actions depending on the conditions present when this middleware is called.
Now we can run this strategy by adding it to the ALL_STRATEGIES
object in index.js
.
Further Reading
From here you can test it out by running the AutoTrade application and selecting the Display Price strategy. To learn more about AutoTrade, read the next article in the series, Part 3 — Creating Your Own AutoTrade Strategy.
Disclaimer: Futures trading and algorithmic trading involve a substantial risk of loss which should be understood prior to trading and may not be suitable for all investors. Therefore, carefully consider whether trading is suitable for you. The information provided in this article is for the sole purpose of education and assistance in making independent investment decisions. Tradovate, LLC has taken reasonable measures to ensure the accuracy of the information contained herein; however, Tradovate, LLC does not guarantee its accuracy, and is not liable for any loss or damage which may arise directly or indirectly from such content or from an inability to access such information, for any delay in or failure of the transmission or the receipt of any instruction or notification in connection therewith. Any recommendations or trading analysis found herein are provided for educational and illustrative purposes only and should not be used in connection with the formation or execution of any trading decisions.
Any opinions, news, research, analyses, prices, reports, graphs, charts, or other information contained herein is provided for informational purposes only and does not constitute investment advice or recommendations. Tradovate, LLC is not liable for any loss or damage, including without limitation, any loss of profit, which may arise directly or indirectly from use of or reliance on any such information. You acknowledge and agree that you bear responsibility for your own investment research and investment decisions, and that Tradovate, LLC shall not be held liable by you or any others for any decision made or action taken by you or others based upon reliance on or use of information or materials obtained or accessed through use of Tradovate, LLC.
Please read carefully the CFTC required disclaimer regarding hypothetical results below.
HYPOTHETICAL PERFORMANCE RESULTS HAVE MANY INHERENT LIMITATIONS, SOME OF WHICH ARE DESCRIBED BELOW. NO REPRESENTATION IS BEING MADE THAT ANY ACCOUNT WILL OR IS LIKELY TO ACHIEVE PROFITS OR LOSSES SIMILAR TO THOSE SHOWN. IN FACT, THERE ARE FREQUENTLY SHARP DIFFERENCES BETWEEN HYPOTHETICAL PERFORMANCE RESULTS AND THE ACTUAL RESULTS SUBSEQUENTLY ACHIEVED BY ANY PARTICULAR TRADING PROGRAM.
ONE OF THE LIMITATIONS OF HYPOTHETICAL PERFORMANCE RESULTS IS THAT THEY ARE GENERALLY PREPARED WITH THE BENEFIT OF HINDSIGHT. IN ADDITION, HYPOTHETICAL TRADING DOES NOT INVOLVE FINANCIAL RISK, AND NO HYPOTHETICAL TRADING RECORD CAN COMPLETELY ACCOUNT FOR THE IMPACT OF FINANCIAL RISK IN ACTUAL TRADING. FOR EXAMPLE, THE ABILITY TO WITHSTAND LOSSES OR TO ADHERE TO A PARTICULAR TRADING PROGRAM IN SPITE OF TRADING LOSSES ARE MATERIAL POINTS WHICH CAN ALSO ADVERSELY AFFECT ACTUAL TRADING RESULTS. THERE ARE NUMEROUS OTHER FACTORS RELATED TO THE MARKETS IN GENERAL OR TO THE IMPLEMENTATION OF ANY SPECIFIC TRADING PROGRAM WHICH CANNOT BE FULLY ACCOUNTED FOR IN THE PREPARATION OF HYPOTHETICAL PERFORMANCE RESULTS AND ALL OF WHICH CAN ADVERSELY AFFECT ACTUAL TRADING RESULTS.