Discover the fascinating “Finite State Machine”

Aug 20, 2022 | EasyLanguage

Finite State Machine: Premise

An important component of the Turtle algorithm was to skip the next 20-day breakout if the previous one was a winner. I assume Dennis believed that the success/failure of a trade had an impact on the outcome of the subsequent trade. I’ve written about how you can implement this in EasyLanguage in previous posts, but I’ve gotten some questions about implementing FSM in commerce and thought this post might kill two birds with one stone: 1) provide a template that can be adapted to any The LTL mechanism and 2) provide the code/structure to configure an FSM using the EasyLanguage Switch/Case structure.

Turtle Specific LTL Logic

Turtle LTL logic states that a trade is a loser if there is a loss of 2N after entry. N is basically an exponential moving average of TrueRange. So if the market moves 2N against a long or short position and you stop it, you have a losing trade. What makes the Turtle algorithm a bit more difficult is that it can also exit at a new 10 day low/high depending on your position. The final departure of 10 days does not mean a loss. Well, at least in this post it’s not like that. I have code that says any loss is a loss, but for this explanation, stick to a 2N loss to determine the failure of an operation.

How to monitor operations when some of them are skipped

This is another additional layer of complexity. You have to do your own trade bookkeeping behind the scenes to determine if a losing trade occurs. Because if you have a winning trade, you skip the next trade, and if you skip that trade, how do you know if you would have been a winner or a loser? You have to run a theoretical system in parallel with the code of the real system.

Ok, let’s start by assuming that the last trade was a winner. So we disabled real trading. As the bars go by, we look for a 20-day penetration high or low. Suppose a new 20-day high is placed and a long position is established at the previous 20-day high. At this point, calculate an amount of 2N and subtract si from the theoretical entry price to get the theoretical exit price. So you have a theoMP (marketPosition) and a theoEX (exit price). This task seems simple enough, so go ahead and start looking for a day that makes a new 10-day low or crosses below your theoEX price. If a new 10-day low is placed then continue to look for a new entry and a subsequent 2N loss. If a loss of 2N occurs, it turns operations back on and continues to monitor operations, turning operations off and on again when necessary. In the following code I use these variables:

  • state – 0: looking for an input or 1: looking for an output
  • lep – long entry price
  • sep – short entry price
  • seekLong – I am looking for a long position
  • seekShort : I am looking for a short position
  • theoMP – theoretical market position
  • theoEX – theoretical starting price
  • lxp – long starting price
  • sxp – short starting price

Let’s jump into the Switch / Case structure when state = 0:

		Case 0:
			lep = highest(h[1],20) + minMove/priceScale;
			sep = lowest(l[1],20) - minMove/priceScale;
			If seekLong and h >= lep then 
				theoMP = 1;
				theoEX = maxList(lep,o) - 2 * atr; 
//				print(d," entered long >> exit at ",theoEX," ",atr);
			If seekShort and l <= sep then 
				theoMP = -1;
				theoEX = minList(sep,o) + 2 * atr;
			If theoMP <> 0 then 
				state = 1;
				cantExitToday = True;

State 0 (Finite State Set Up)

The Switch / Case is an essential structure in any programming language. What really surprises me is that Python doesn’t have it. They claim it’s redundant to an if-then structure and it is, but it’s much easier to read and implement. Basically you use the Switch statement and a variable name and based on the value of the variable it will flow to whatever case the variable is equal to. Here we are looking at state 0. In the CASE: 0 structure, the computer calculates the lep and sep values – long and short input levels. If it is flat, then you are looking for a long or short position. If the bar’s high or low penetrates their respective trigger levels, then the oMP is set to 1 for long or -1 for short. TheoEX is then calculated based on the atr value on the day of entry. If theoMP is set to 1 or -1, then we know that an operation has just been triggered. The finite state machine then changes gear to state 1. Since State = 1, the next Case statement is evaluated immediately. I don’t want to exit on the same bar I entered (wide bars can come and go during volatile times). I use a cantExitToday variable. This variable delays the evaluation of Case 1: one bar.

Status = 1 code:

	Case 1:
		If not(cantExitToday) then
			lxp = maxList(theoEX,lowest(l[1],10)-minMove/priceScale);
			sxp = minList(theoEX,highest(h[1],10)+minMove/priceScale);	
			If theoMP = 1 and l <= lxp then
				theoMP = 0;
				seekLong = False;
				if lxp <= theoEX then 
					ltl = True
					ltl = False;
			If theoMP =-1 and h >= sxp then
				theoMP = 0;
				seekShort = False;
				if sxp >= theoEX then 
					ltl = True
					ltl = False;
			If theoMP = 0 then state = 0;
		cantExitToday = False;	

State = 1 (Switching Gears)

Once we have a theoretical position, we just examine the code in the module Case 1: On the next bar after the entry, lxp and sxp (long exit and short exit prices) are calculated. Note that these values use maxList or minList to determine which is closer to the current market action: the 2N stop or the 10-day low/high low/high. Lxp and sxp are assigned whichever is closest. The high or low of each bar is compared to these values. If theoMP = 1 then bass is compared to lxp. If the downside crosses below lxp, then things get moving. TheoMP is immediately set to 0 and seekLong is returned to False. If lxp <= a 2N loss, then ltl (last trade loser) is set to true. Otherwise, ltl is set to False. If theoMP = 0, then we assume a flat position and change the FSM back to state 0 and start looking for a new trade. The ltl variable is then used in the code to allow an actual exchange to happen.

The strategy incorporates our FSM product

If barNumber = 1 then n = avgTrueRange(20);
if barNumber > 1 then n = (n*19 + trueRange)/20;

If useLTLFilter then
	if ltl then buy next bar at highest(h,20) + minMove/priceScale stop;
	if ltl then sellShort next bar at lowest(l,20) -minMove/priceScale stop;
	buy next bar at highest(h,20) + minMove/priceScale stop;
	sellShort next bar at lowest(l,20) -minMove/priceScale stop;

mp = marketPosition;

If mp <> 0 and mp[1] <> mp then NLossAmt = 2 * n;

If mp = 1 then
	Sell("LL10-LX") next bar at lowest(l,10) - minMove/priceScale stop;
	Sell("2NLS-LX") next bar at entryPrice - NLossAmt stop;
If mp =-1 then
	buyToCover("HH10-SX") next bar at highest(h,10) + minMove/priceScale stop;
	buyToCover("2NLS-SX") next bar at entryPrice + NLossAmt stop;

Strategy Code Using LTL filter

This code basically replicates what we did in the FSM, but places actual orders based on the fact that the last trade was a loser (ltl.)

Works? Only trade after a 2N loss

LTLExample 1

No filter in the last 10 years in crude


With filter in the last 10 years in crude

I have programmed this into my TradingSimula-18 software and will show portfolio performance with this filter a bit later on

I had to do a bit of tinkering with some codes due to the fact that you can exit and re-enter the same bar. In the next post of this blog I will tell you about those machinations. With this template, you should be able to recreate any last trade that was a losing mechanism and see if it can help you with your own trading algorithms.

Article courtesy of George Pruitt

Quantified Models Youtube Channel

On our YouTube channel we have several videos available that you may find very useful for developing trading systems. To access, click this link: Quantified Models YouTube Channel

We hope this information has been useful to you.

Subscribe to our Newsletter

Join our mailing list to receive the latest news and updates from Quantified Models team.

Subscribe to our Newsletter

You have Successfully Subscribed!

Skip to content