Jeff Swanson wrote a great post on multi-agent trading a few years ago.
Jeff created a simple mean reversion system and then created two derivatives that culminated in three systems (or three agents.) Using Murray Ruggiero’s Equity Curve Feedback, he was able to poll which system was doing the best, synthetically, and execute the strategy that showed the best performance. If memory serves, picking the highflyer turned out to be the way to go. Jeff had just touched the surface of Murray’s tool. but it definitely did the job. Murray contracted me to fix some problems with the ECF tool and I did, but the tool is just way too cumbersome, resource hungry and requires a somewhat higher level of EasyLanguage knowledge to be universally applicable. I was doing similar research in the area of polling multiple strategies and picking the best, just like Jeff did, and just executing that one system, when I thought about this post. Traders do this all the time. They have multiple strategies in the pipeline and monitor the performance and if one is head and shoulders better than what they are currently trading, they will switch systems. This was one of the side benefits of the ECF tool.
What is an agent
An agent is any trading system that produces a positive expectancy. Using multiple agents in a polling process allows a trader to go with the strategy that is currently performing the best. This sounds reasonable, but there are pitfalls. You could always be behind the curve – picking the best system right before it has its draw down. Agents can be similar, or they can be totally different types of systems. I am going to follow in Jeff’s footsteps and create three agents with the same DNA. Here is what I call the AgentSpawner strategy.
This code trades in the direction of the longer-term moving average and waits for a pull back on N consecutive down closes. I am using the neat function countIF. This function counts the number of times the conditional test occurs in the last N bars. If I want to know the number of times I have had a down close in the last 3 days, I can use this function like this.
If the close is greater than the longer-term moving average and I have N consecutive down closings, then I buy the next bar at the open. I use a wide protective stop and get out after X bars since entry. Remember EasyLanguage does not count the day of entry in its barsSinceEntry calculation. I am not using the built-in setStopLoss as I don’t want to get stopped out on the day of entry. In real trading, you may want to do this, but for testing purposes my tracking algorithm was not this sophisticated. I spawned three agents with the following properties.
System Tracking Algorithm
This is why I love copy-paste programming. This can be difficult if you don’t know your EasyLanguage or how TradeStation processes the bars of data. Get educated by checking my books out at amazon.com – that is if you have not already. This code is a very simplistic approach for keeping track of a system’s trades and its equity.
I am pretending to be TradeStation here. First, I need to test to see if Agent#1 entered into a long position. If the close of yesterday is greater than the moving average, inclusive of yesterdays close, and there has been two consecutive down closes, then I know a trade should have been entered on todays open. EasyLanguage’s next bar paardigm cannot be utilized here. Remember I am not generating signals, I am just seeing if today’s (not tomorrows or the next bars) trading action triggered a signal and if so, I need to determine the entry/exit price. I am gathering this information so I can feed it into a series function. If a trade is triggered, I set four variables:
- sys1Signal – 1 for long, -1 for short, and 0 for flat.
- sys1BarCount – set to a -1 because I immediately increment.
- sys1TradePrice – at what price did I enter or exit
- sys1LExit – set this to our stop loss level
If I am theoretically long, remember we are just tracking here, then I need to test, starting with the following day, if the low of the day is below our stop loss level and if it is I need to reset two variables:
- sys1TradePrice – where did I get out
- sys1Signal – set to 0 for a flat position
If not stopped out, then I start counting the number of bars sys1Signal is equal to 1. If sys1BarCount = 16, then I get out at the open by resetting the following variables:
- sys1TradePrice = open
- sys1Signal = 0
If you look back at the properties for Agent#1 you will see I get out after 15 days, not 16. Here is where the next bar paradigm can make it confusing. The AgentSpawner strategy says to sell next bar at open when barsSinceEntry = 15. The next bar after 15 is 16, so we store the open of the 16th bar as our trade price.
Now copy and paste the code into a nice editor such as NotePad++ or NotePad and replace the string sys1 with sys2. Copy the code from NotePad++ into your EasyLanguage editor. Now back to NotePad++ and replace sys2 with sys3. Copy that code into the EL edition too. Now all you need to do is change the different properties for each agent and you will have three tracking modules.
The Power of the EasyLanguage Series Function
The vanilla version of EasyLanguage has object-oriented nuances that you may not see right off the bat. In my opinion, a series function is like a class. Before I get started, let me explain what I mean by series. All EasyLanguage function are of three types.
- simple – like a Bollinger band calculation
- series – like we are talking about here
- auto-detect – the interpreter/compiler decides
The series function has a memory for the variables that are used within the function. Take a look at this.
On the first bar of the function call – remember it will be called on each bar in the chart, the function variable count is assigned seed. Seed will be ignored on subsequent bars. What makes this magical is that no matter how many times you call the function on the same bar it remembers the internal variables on somewhat of a hierarchical basis (each call remembers its own stuff.) It like a class in that it gets instantiated on the very first call. Meaning if you call it three times on the first bar of the data, you will have three distinct internal variable memories. Take a look at my sandbox function driver and its output.
Why is this important?
I have created a PLSimulator function that keeps track of the three agent’s performance. I need the profit or loss to stick with each function and then also add or subtract from it. This is a neat function. Remember if you like this stuff buy my books at Amazon.com.
Feed tracker algorithm data into the function
Your information must be properly assigned to get this to work. First, I show how to get the information into the function. The function does all the work and returns the equity. I then determine the best agent by looking at the ROC over the past thirty days of equity for each agent and pick the very best. I then trade the very best. This is a very quick application of the function. I will have a more sophisticated function, something akin to Murray’s ECF but with much less overhead and more strategy templates.
If this seems over your head…
Get one of my books are check out Jeff Swanson’s course. EasyLanguage has so many little nuggets that can help you define your algorithm into an actionable strategy. You will never know how your strategy will work until your program it (properly) and back test it. And then potentially improve it with optimization.
Multi-Agent Results
Discover more from George Pruitt
Subscribe to get the latest posts sent to your email.