Last month’s post on using the elcollections dictionary was a little thin so I wanted to elaborate on it and also develop a trading system around the best patterns that are stored in the dictionary. The concept of the dictionary exists in most programming languages and almost all the time uses the (key)–>value model. Just like a regular dictionary a word or a key has a unique definition or value. In the last post, we stored the cumulative 3-day rate of return in keys that looked like “+ + – –” or “+ – – +“. We will build off this and create a trading system that finds the best pattern historically based on average return. Since its rather difficult to store serial data in a Dictionary I chose to use Wilder’s smoothing average function.
Ideally, I Would Have Liked to Use a Nested Dictionary
Initially, I played around with the idea of the pattern key pointing to another dictionary that contained not only the cumulative return but also the frequency that each pattern hit up. A dictionary is designed to have unique key–> to one value paradigm. Remember the keys are strings. I wanted to have unique key–> to multiple values. And you can do this but it’s rather complicated. If someone wants to do this and share, that would be great. AndroidMarvin has written an excellent manual on OOEL and it can be found on the TradeStation forums.
Ended Up Using A Dictionary With 2*Keys Plus an Array
So I didn’t want to take the time to figure out the nested dictionary approach or a vector of dictionaries – it gets deep quick. So following the dictionary paradigm I came up with the idea that words have synonyms and those definitions are related to the original word. So in addition to having keys like “+ + – -” or “- – + -” I added keys like “0”, “1” or “15”. For every + or – key string there exists a parallel key like “0” or “15”. Here is what it looks like:
– – – –
=
“0”
– – – +
=
“1”
– – + –
=
“2”
You can probably see the pattern here. Every “+” represents a 1 and every “0” represent 0 in a binary-based numbering system. In the + or – key I store the last value of Wilders average and in the numeric string equivalent, I store the frequency of the pattern.
Converting String Keys to Numbers [Back and Forth]
To use this pattern mapping I had to be able to convert the “++–” to a number and then to a string. I used the numeric string representation as a dictionary key and the number as an index into an array that store the pattern frequency. Here is the method I used for this conversion. Remember a method is just a function local to the analysis technique it is written.
//Lets convert the string to unique number method int convertPatternString2Num(string pattString) Vars: int pattLen, int idx, int pattNumber; begin pattLen = strLen(pattString); pattNumber = 0; For idx = pattLen-1 downto 0 Begin If MidStr(pattString,pattLen-idx,1) = "+" then pattNumber = pattNumber + power(2,idx); end; Return (pattNumber); end;
String Pattern to Number
This is a simple method that parses the string from left to right and if there is a “+” it is raised to the power(2,idx) where idx is the location of “+” in the string. So “+ + – – ” turns out to be 8 + 4 + 0 + 0 or 12.
Once I retrieve the number I used it to index into my array and increment the frequency count by one. And then store the frequency count in the correct slot in the dictionary.
patternNumber = convertPatternString2Num(patternString); //Keep track of pattern hits patternCountArray[patternNumber] = patternCountArray[patternNumber] + 1; //Convert pattern number to a string do use as a Dictionary Key patternStringNum = numToStr(patternNumber,2); //Populate the pattern number string key with the number of hits patternDict[patternStringNum] = patternCountArray[patternNumber] astype double;
Store Value In Array and Dictionary
Calculating Wilder’s Average Return and Storing in Dictionary
Once I have stored an instance of each pattern [16] and the frequency of each pattern[16] I calculate the average return of each pattern and store that in the dictionary as well.
//Calculate the percentage change after the displaced pattern hits Value1 = (c - c[2])/c[2]*100; //Populate the dictionary with 4 ("++--") day pattern and the percent change if patternDict.Contains(patternString) then Begin patternDict[patternString] = (patternDict[patternString] astype double * (patternDict[patternStringNum] astype double - 1.00) + Value1) / patternDict[patternStringNum] astype double; end Else begin patternDict[patternString] = value1; // print("Initiating: ",patternDict[patternString] astype double); end;
(pAvg * (N-1) + return) / N
When you extract a value from a collection you must us an identifier to expresses its data type or you will get an error message : patternDict[patternString] holds a double value {a real number} as well as patternDict[patternStringNum] – so I have to use the keyword asType. Once I do my calculation I ram the new value right back into the dictionary in the exact same slot. If the pattern string is not in the dictionary (first time), then the Else statement inserts the initial three-day rate of return.
Sort Through All of The Patterns and Find the Best!
The values in a dictionary are stored in alphabetic order and the string patterns are arranged in the first 16 keys. So I loop through those first sixteen keys and extract the highest return value as the “best pattern.”
// get the best pattern that produces the best average 3 bar return vars: hiPattRet(0),bestPattString(""); If patternDict.Count > 29 then Begin index = patternDict.Keys; values = patternDict.Values; hiPattRet = 0; For iCnt = 0 to 15 Begin If values[iCnt] astype double > hiPattRet then Begin hiPattRet = values[iCnt] astype double ; bestPattString = index[iCnt] astype string; end; end; // print(Date," BestPattString ",bestPattString," ",hiPattRet:8:4," CurrPattString ",currPattString); end;
Extract Best Pattern From All History
If Today’s Pattern Matches the Best Then Take the Trade
// if the current pattern matches the best pattern then bar next bar at open If currPattString = BestPattString then buy next bar at open; // cover in three days If barsSinceEntry > 2 then sell next bar at open;
Does Today Match the Best Pattern?
If today matches the best pattern then buy and cover after the second day.
Conclusion
I didn’t know if this code was worth proffering up but I decided to posit it because it contained a plethora of programming concepts: dictionary, method, string manipulation, and array. I am sure there is a much better way to write this code but at least this gets the point across.
var: patternTest(""),tempString(""),patternString(""),patternStringNum(""); var: patternNumber(0); var: iCnt(0),jCnt(0); //Lets convert the string to unique number method int convertPatternString2Num(string pattString) Vars: int pattLen, int idx, int pattNumber; begin pattLen = strLen(pattString); pattNumber = 0; For idx = pattLen-1 downto 0 Begin If MidStr(pattString,pattLen-idx,1) = "+" then pattNumber = pattNumber + power(2,idx); end; Return (pattNumber); end;
once begin clearprintlog; patternDict = new dictionary; index = new vector; values = new vector; end;
//Convert 4 day pattern displaced by 2 days patternString = ""; for iCnt = 5 downto 2 begin if(close[iCnt]> close[iCnt+1]) then begin patternString = patternString + "+"; end else begin patternString = patternString + "-"; end; end;
//What is the current 4 day pattern vars: currPattString(""); currPattString = "";
for iCnt = 3 downto 0 begin if(close[iCnt]> close[iCnt+1]) then begin currPattString = currPattString + "+"; end else begin currPattString = currPattString + "-"; end; end;
//Get displaced pattern number patternNumber = convertPatternString2Num(patternString); //Keep track of pattern hits patternCountArray[patternNumber] = patternCountArray[patternNumber] + 1; //Convert pattern number to a string do use as a Dictionary Key patternStringNum = numToStr(patternNumber,2); //Populate the pattern number string key with the number of hits patternDict[patternStringNum] = patternCountArray[patternNumber] astype double; //Calculate the percentage change after the displaced pattern hits Value1 = (c - c[2])/c[2]*100; //Populate the dictionary with 4 ("++--") day pattern and the percent change if patternDict.Contains(patternString) then Begin patternDict[patternString] = (patternDict[patternString] astype double * (patternDict[patternStringNum] astype double - 1.00) + Value1) / patternDict[patternStringNum] astype double; end Else begin patternDict[patternString] = value1; // print("Initiating: ",patternDict[patternString] astype double); end; // get the best pattern that produces the best average 3 bar return vars: hiPattRet(0),bestPattString(""); If patternDict.Count > 29 then Begin index = patternDict.Keys; values = patternDict.Values; hiPattRet = 0; For iCnt = 0 to 15 Begin If values[iCnt] astype double > hiPattRet then Begin hiPattRet = values[iCnt] astype double ; bestPattString = index[iCnt] astype string; end; end; // print(Date," BestPattString ",bestPattString," ",hiPattRet:8:4," CurrPattString ",currPattString); end; // if the current pattern matches the best pattern then bar next bar at open If currPattString = BestPattString then buy next bar at open; // cover in three days If barsSinceEntry > 2 then sell next bar at open;
George Pruitt’s Easing into EasyLangauge – Academy
A video-based approach to teaching EasyLanguage. Learn at your own pace.
Module #1
and Pattern Smasher 2024 too!
From the creator of the bestselling Easing into EasyLanguage series comes his latest project – Easing into EasyLanguage Academy. In this introductory course, George shows you to program a George Taylor Technique into a day trading system. You will start with a blank slate and learn everything you need to take advantage of Taylor’s Buy and Short – day techniques. Give the gift the keeps on giving – knowledge.
Can You Program This Trading Strategy?
Imagine this: On a buy day, you want to:
Enter: Place a buy order for tomorrow if the market:
Trades a certain amount below today’s low, and
Then travels back up to today’s low.
Protect: Use a protective stop at tomorrow’s low (before the buy stop is triggered).
Risk Manage: If the entry and exit levels are too large, limit your risk to a predefined amount.
Profit Secure: When a specific profit level is reached, implement a ratcheting trailing stop to lock in a percentage of the maximum open trade equity.
Time Manage: If still in the trade at a specific time of day, exit the position.
PURCHASE NOW AND GET PATTERN SMASHER 2024 FOR FREE!
Learn how to do this and then pick intelligent and robust paremeter sets.s
Get the Pattern Smasher Cheat Code to create this strategy. This is a 4 Pattern relationship based on the last three day’s closing relationships. You can learn more at George’s Digital Store.