Under this plan, we stop trading if our account size drops below the margin of a one lot. We divide our money evenly across different systems and markets after seeing how many markets we have across all the sessions. We set the unit size to one contract so we minimize size granularity and can add units quicker. Control is given to this code after each system is run in parallel for the minimum time frame of any of the systems. If the smallest time frame of any system is five-minute bars, we will run that system for a five-minute bar and not run the daily systems until the end of the day.
Once we get control back, we loop through each session and each market in each session. The EntryNumUnits is an object at the market level. If we set EntryNumUnits to zero, we override the size, which effectively skips the trade. If we have enough money to trade that market, then we size the same by dividing the money per market by margin. We use the Min function so we can set a ceiling. Otherwise, if we run a simulation for 20 years, it’s possible that we could buy more contracts than we could actually trade, so this allows us to set a maximum number of contracts. We also have an ExitNumUnits, which we can set for each market. In our case, we set it to the number of contracts held:
Let’s see how this works for each market for which we are setting EntryNumUnits. We have a $250,000 account and are trading 10 markets. This means DollarsPerMarket will be $25,000. If we are using a percent margin of 25%, then we would multiply $25,000 by 0.25, giving us $6,250 per market. If we are trading the 10-year Treasury note with a margin of $2,800, we would trade a floor of $6,250/$2,800, or two contracts. SummEquity object gives us the current account size, including both closed and open profits. Using open profits in futures can cause us to get too much leverage during big trends. We could adjust for this easily, using the code fragment below:
If tradeplan.OpenPandL>0 then
DollarsPerMarket=(tradeplan.SummEquity- .25*tradeplan.OpenPandL )/NumberOfMarkets
If we replace DollarsPerMarket = tradeplan.SummEquity/NumberOfMarkets with the code above, we would use only 25% of the open profit toward reinvestment. A trend following system often can give back 50% or more of open profits. Open profits can, in rare cases, be almost as much as closed profits for 10 years if we have monster trends. This can create a volatile equity curve.
The percentage margin plan is a simple sizing algorithm. The problem is that margin is not changed often and may not be a good measure of current volatility. Also, margins change over time and historical margin data may or may not be available for your market. A solution is to use dynamic margin instead. It’s based on current volatility (find the code online at futuresmag.com/systemcodes).
We use an average true range times the value of a full point in the market. Finally, we multiply by a constant MarginEST, for margin estimate, we normally use a value between 5.0 and 8.0 for this, and replace margin with the value returned from this function. Dynamic margin performs better than standard margin as it reduces risk by adjusting more quickly to market conditions than the exchanges.
Trade plan concepts
Another classic trade plan solution uses ranking. There are two ways to accomplish this with an account of $100,000 or less. One is to create a small portfolio that can be traded within that account size. Another is to trade a larger portfolio but use ranking to take only a given number of positions. For example, you can add 15 markets in a portfolio to trade a trend-following system and only trade the five with the highest average directional index (ADX) values and limit trades to five positions. In addition, you can exit positions if the ADX drops below the top five (the code for this is at futuresmag.com/systemcodes).
This code lets us set ADX ranking both ways. If we use -1 as mmode then we subtract 50 from ADX, we will now rank from lowest ADX to highest. If mmode is not -1, it will select MaxPosition, starting at highest ADX values. LB is the period used in the ADX calculations. We can do ranking based on any objective function we want. We can create a function that produces an array of three columns: symbol, raw ranking value and a true/false column. We can then set that to IsActiveOrder values because we only want to rank functions that have a valid active order:
This function gives us a global ranking regardless of active orders, as well as a ranking within active orders. Our logic in the trade plan code shown earlier will add one or two positions per day, depending on how many positions we have left. If we have one position left, then we will only take the top ranked active order. If we have two positions left, then we will take the top two active orders. The global rank is the rank among all markets, not just ones with active orders. The iActiveOrderCount is the rank within active orders. We can set a property to make the rank be returned relative or ordinal. Ordinal is used in this example.