In the Pascal programming language you have Procedures and Functions. Procedures are used when you want to modify multiple variables within a sub-program. A function is a sub-program that returns a single value after it has been modified by say a formula. EasyLanguage combines procedures and functions into one sub-program called a function. Functions and procedures both have a formal parameter definition – a list that describes the type of parameters that are being received by the calling program. In Pascal procedures, you pass the address of the value that you want changed. By modifying the contents of the address you can pass the value back and forth or in and out of the procedure. In functions you pass by value. Remember the parameter in a normal function call is used to instruct something within the body of the function and is not altered (e.g. the number 19 in value1 = average(c,19)). This value doesn’t need to be modified it’s just used. Look at the following code:
Here I am modifying mav1, mav2 and mav3 within the function and then passing the values back to the calling strategy/indicator/paintbar. All functions must return a value so I simply assign the value 1 to the function name. The key here is the keyword numericRef, once I change the values located in the addresses of mav1, mav2 and mav3 (address are provided by the keyword numericRef), they will be made available to the calling program. This code allows the function to return more than just one value.
I have started using the TDE’s projects more and more. Before, when I was working on multiple related files I would lose track of them in the editor tabs, or discover, when working over time on different projects, I would have twenty or thirty files open – this of course would slow the editor down. Using projects can clean up your workspace and speed up productivity. Projects have been around forever and most professional IDEs incorporate them to aid in the organization and productivity of the programmer.
Here is simple Project with three components: indicator, function, and strategy.
Notice how you can focus just on the components of the project.
I also like to split the editor window and populate the bottom pane with code I might need to refer.
Check out the multiple output function – geoTriMavIndic.
A reader of the “UATSTB” asked for an example of how to pyramid in the Python System BackTester (PSB). I had original bug where you couldn’t peel off all of the positions at once. If you tried then the PSB would crash. I have now fixed that problem and here are the necessary lines to add on another position after the initial positions is put on. I am using a simple moving average crossover to initiate the first position and then if the longer term moving average is positive for 4 days in a row I add on another position. That’s it. A max of two position only. The system either gets reversed to the other side, stopped out or takes profits. Attached in this post is the module that fixes the pyramiding problem and the code for this system in its entirety. I will also put the fix in the version 2.0 download.
upCnt = 0 dnCnt = 0 for j in range(4): if sAverage(myClose,39,i,j) > sAverage(myClose,39,i,j+1): upCnt += 1 if sAverage(myClose,39,i,j) < sAverage(myClose,39,i,j+1): dnCnt += 1
#Long Entry Logic if (mp != 1) and avg1 > avg2 and prevAvg1 < prevAvg2: profit = 0 price = myClose[i] tradeName = "DMA Buy"
#Long Pyramid Logic if (mp == 1) and upCnt == 4: profit = 0 price = myClose[i] tradeName = "LongPyra"
Pyramiding the Long Side of a Dual Moving Average
I only put in the summary of code that will create the initial position and then add 1 more. Notice the highlighted code from line 3 to 7. Here I am using a simple loop to determine if the the 39-day moving average is increasing/decreasing consecutively over the past four days. If the upCnt == 4 then I add a long position. Notice how I test in the Long Pyramid Logic the values of mp and upCnt. I only go long another position if I am already long 1 and upCnt == 4.
While I was posting the trades I found something that struck my funny – look at line 5 (highlighted). The short pyramid trade occurs at a higher price than the initial short – at first I thought I had made a programming error. So I thought I would double check the code and then do some debugging. Instead of invoking the debugger which is really cool and easy to use I decided to just print out the results to the console.
for j in range(4): if sAverage(myClose,39,i,j) > sAverage(myClose,39,i,j+1): upCnt += 1 if sAverage(myClose,39,i,j) < sAverage(myClose,39,i,j+1): dnCnt += 1 if tempDate == 20041119: print(myDate[i]," ",j," ",sAverage(myClose,39,i,j))
'''Output of debugging using a print statement 20041119 0 130.68692307692308 20041119 1 130.69538461538463 20041119 2 130.74871794871794 20041119 3 130.7723076923077'''
Debugging using Print Statements
As you can see the longer term moving average is moving down event though price has increased. Take a look at this chart and you can see multiple occurrences of this.
Remember to copy and replace the tradeClass.py in you PSB2.0 directory – this fixes the pyramid bug. Also copy the DMAPyra.py to the same directory. If you haven’t as of yet download the PSB from this website and buy the book for a very good description.
Here is some code I have been working on. I will go into detail on the code a little later. But this is how you monitor re-entering at a better price after taking a profit. The problem with taking profits on longer term trend following systems is that the logic that got you into the position is probably still true and you will notice your algorithm will re-enter in the same direction. So you need to inform your algorithm not to re-enter until a certain condition is met. In this example, I only re-enter at a better price if the condition that got me into the trade is still valid.
if not(longProfTaken) and mp <> 1 then Buy("BreakOut-B") next bar at highest(h[1],20) on a stop; if not(shortProfTaken) and mp <>-1 then SellShort("BreakOut-S") next bar at lowest(l[1],20) on a stop;
//If mp[0] = 0 and mp[1] = 1 then print(date," ",exitPrice(1)," ",entryPrice(1));
If longProfTaken then Begin If c < exitPrice(1) - getBackInAfterProfAmt$/bigPointValue then begin longProfTaken = false; If mp <> -1 then buy("longRe-Entry") next bar at open; end; end;
If shortProfTaken then Begin If c > exitPrice(1) + getBackInAfterProfAmt$/bigPointValue then begin shortProfTaken = false; If mp <>-1 then sellShort("shortRe-Entry") next bar at open; end; end;
If mp = 1 and c > entryPrice + profitAmt$/bigPointValue then begin sell this bar on close; longProfTaken = true; end;
If mp =-1 and c < entryPrice - profitAmt$/bigPointValue then begin buyToCover this bar on close; shortProfTaken = true; end;
If mp = -1 then longProfTaken = false; If mp = 1 then shortProfTaken = false;
//if mp = 1 then setStopLoss(stopAmt$); //if mp = 1 then setProfitTarget(profitAmt$);
Okay let’s see how I was able to add some eloquence to the brute force approach to this pyramiding algorithm. The original code included multiple entry directives and a ton of hard coded numerical values. So let me show you how I was able to refine the logic/code and in doing so make it much more flexible. We might lose a little bit of the readability, but we can compensate by using extra commentary.
First off, let’s add flexibility by employing input variables. In this case, we need to inform the algorithm the distance from the open to add additional positions and the max number of entries allowed for the day.
inputs : pyramidDistance(5),maxDailyEntries(3);
Now we need to set somethings up for the first bar of the day. Comparing the date of today with the date of yesterday is a good way to do this.
if d<>d[1] then begin canSell = true; sellMult = 1; sellStop = -999999; entries = 0; end;
First bar of the day housekeeping.
Here is a neat way to keep track of the number of entries as they occur throughout the trading day. Remember the function EntriesToday(date) will not provide the information we need.
mp = marketPosition * currentShares;
if mp[1] <> mp and mp <> 0 then entries = entries + 1;
How to track the number of entries for today.
If the last bar’s mp[1] is not equal to the current bar’s mp then and mp is not equal to zero then we know we have added on another entry. Okay now let’s think about eliminating the “brute force” approach.
Instead of placing multiple order entry directives I only want to use one with a variable stop level. This stop level will be guided by the variable SellMult. We start the day with a wacky sell stop level and then calculate it based on the SellMult variable and PyramidDistance input.
if low <= sellStop then begin sellMult = sellMult + 1; end;
sellStop = openD(0) - sellMult * pyramidDistance;
Calculate and adapt sell stop level as we go along.
So on the first bar of the day the sellStop = openD(0) – sellMult * pyramidDistance or sellStop = openD(0) – 1 * 5. Or 5 handles below the open. Note you an change the pyramidDistance input and make it three to match the previous examples.
if entries = maxDailyEntries then canSell = false; if time < sess1EndTime and canSell then sellShort 1 contract next bar at sellStop stop; if mp <=-1 {and barsSinceEntry > 0} then buyToCover next bar at sellStop + 2* pyramidDistance stop;
setexitonclose;
That's it! Pretty simple isn't it?
Ok, we need to tell the computer to turn off the ability to place orders if one of two things happens: 1) we have reached the maxDailyEntries or 2) time >= sess1EndTime. You could make the time to stop entering trades an input as well. If neither criteria applies then place an order to sellShort at our sellStop level. If price goes below our sell stop level then we know we have been filled and the new sellStop level needs to be recalculated. See how we use a calculation to adapt the stop level with a single order placement directive? This is where the eloquence comes into play. QED.
Now you code the opposite side and then see if you can make money (hypothetically speaking of course) with it. If you think about it, why does this not work. And the not so obvious reason is that it trades too much. Other than trading too much it makes perfect sense – buy or sell by taking a nibbles at the market. If the market takes off then take a big bite. The execution costs of the nibbles are just way too great. So we need to think of a filtering process to determine when it is either better to buy or sell or when to trade at all. Good Luck with this ES [emini S&P ]day trading algorithm!
if d<>d[1] then begin canSell = true; sellMult = 1; sellStop = -999999; entries = 0; end;
mp = marketPosition * currentShares;
if mp[1] <> mp and mp <> 0 then entries = entries + 1; if mp[1] = -1 and mp[0] = 0 then canSell = false; if time > 1430 then canSell = false;
if low <= sellStop then begin sellMult = sellMult + 1; end;
sellStop = openD(0) - sellMult * pyramidDistance; if entries = maxDailyEntries then canSell = false; if time < sess1EndTime and canSell then sellShort 1 contract next bar at sellStop stop; if mp <=-1 {and barsSinceEntry > 0} then buyToCover next bar at sellStop + 2* pyramidDistance stop;
Sorry for the delay in getting this up on the web. Here is the flip side of the pyramiding day trade scheme from the buy side perspective. I simply flipped the rules. In some cases, to keep the programming a little cleaner I like to keep the buy and sellShort logic in two separate strategies. So with this chart make sure you insert both strategies.
And here is the code:
vars: mp(0),lastTradePrice(0),canBuy(true);
mp = marketPosition * currentContracts;
if date[0] <> date[1] then begin canBuy = true; end;
if mp = 1 then canBuy = false; if time > 1430 then canBuy = false;
if mp = 0 and canBuy = true then buy next bar at OpenD(0) + 3 stop; if mp = 1 then buy next bar at OpenD(0) + 6 stop; if mp = 2 then buy next bar at OpenD(0) + 9 stop;
if mp = 1 then lastTradePrice = OpenD(0) + 3; if mp = 2 then lastTradePrice = OpenD(0) + 6; if mp = 3 then lastTradePrice = OpenD(0) + 9;
if mp <> 0 then sell next bar at lastTradePrice - 3 stop;
if mp = 3 and barsSinceEntry > 0 and highD(0) > lastTradePrice + 3 then sell next bar at highD(0) - 3 stop;
Here is the finalized tutorial on building the pyramiding ES-day-trade system that was presented in the last post.
I will admit this video should be half as long as the end result. I get a bit long-winded. However, I think there are some good pointers that should save you some time when programming a similar system.
EasyLanguage Source:
Here is the final code from the video:
vars: mp(0),lastTradePrice(0),canSell(true);
mp = marketPosition * currentContracts;
if date[0] <> date[1] then begin canSell = true; // canSell on every day end;
if mp = -1 then canSell = false; // one trade on - no more if time > 1430 then canSell = false; //no entries afte 230 central
if mp = 0 and canSell = true then sellShort next bar at OpenD(0) - 3 stop;
if mp = -1 then sellShort next bar at OpenD(0) - 6 stop; //add 1 if mp = -2 then sellShort next bar at OpenD(0) - 9 stop; //add 2
if mp = -1 then lastTradePrice = OpenD(0) - 3; //keep track of entryPrice if mp = -2 then lastTradePrice = OpenD(0) - 6; if mp = -3 then lastTradePrice = OpenD(0) - 9;
if mp <> 0 then buyToCover next bar at lastTradePrice + 3 stop; // 3 handle risk on last trade
// next line provides a threshold prior to engaging trailing stop if mp = -3 and barsSinceEntry > 0 and lowD(0) < lastTradePrice - 3 then buyToCover next bar at lowD(0) + 3 stop;
setExitOnClose;
EasyLanguage for Pyramiding and Day-Trading ES
What we learned here:
can’t use entriesToday(date) to determine last entry price
must use logic to not issue an order to execute on the first bar of the next day
mp = marketPosition * currentContracts is powerful stuff!
In the next few days, I will publish the long side version of this code and also a more eloquent approach to the programming that will allow for future modifications and flexibility.
Let me know how it works out for you.
Take this code and add some filters to prevent trading every day or a filter to only allow long entries!
Would you like to learn how to do this? Check back over the next few days and I will show you to do it. Warning: its not straightforward as it seems – some tricks are involved. Remember to sign up for email notifications of new posts.
UPDATE[1]: I have recorded an introductory webcast on how to program this pyramiding scheme. This webcast is Part 1 and illustrates how to brainstorm and start thinking/programming about a problem. Part 1 introduces some concepts that show how you can use and adapt some of EasyLanguage built-in reserved words and functions. I start from the perspective of a somewhat beginning EasyLanguage programmer – one that knows enough to maybe not get the problem solved, but at least get the ball rolling. The final code may not look anything like the code I present in Part 1. However it is sometimes important to go down the wrong trail so that you can learn the limitations of a programming language. Once you know the limitations, you can go about programming workarounds and fixes. I hope you enjoy Part 1 I should have Part 2 up soon. Don’t be too critical, this is really the first webcast I have recorded. You’ll notice I repeat myself and I refer to one function input as a subscript. Check it out: https://youtu.be/ip-DyyKpOTo
A good portion of my readers use MultiCharts and the similarities between their PowerLanguage and EasyLanguage is almost indistinguishable. However, I came across a situation where one my clients was getting different values between an indicator function call and the actual plotted indicator when using Multi-Data.
Here is the code that didn’t seem to work, even though it was programmed correctly in TradeStation.
Value1 = DirMovement( H, L, C , Data1ADXLen, oDMIPlus1, oDMIMinus1, oDMI1, oADX1, oADXR1, oVolty1 ) ; Value2 = DirMovement( H of data2, L of data2, C of data2, Data2ADXLen, oDMIPlus2, oDMIMinus2, oDMI2, oADX2, oADXR2, oVolty2 );
Pretty simple – so what is the problem. Data aliasing was utilized in the Vars: section – this keeps the indicator from being calculated on the time frame of data1. Its only calculated on the data2 time frame – think of data1 being a 5 min. chart and data2 a 30 min. chart. I discovered that you have to also add data aliasing to not just the variables used in the indicator function but also to the function call itself. This line of code fixed the problem:
DirMovement( H of data2, L of data2, C of data2, Value2, oDMIPlus2, oDMIMinus2, oDMI2, oADX2, oADXR2, oVolty2 )data2;
Add data2 after the function call to tie it to data2.
See that! Just add Data2 to the end of the function call. This verifies in TradeStation and compiles in MC with no problems.
I had a request recently to publish the EasyLanguage code for my Dynamic Moving Average system. This system tries to solve the problem of using an appropriate length moving average that will keep you out of the chop. The adaptive engine utilizes market volatility and increases moving average lengths as volatility increases and decreases moving average lengths as volatility decreases. Its had some success, but the adaptive engine has not truly solved the problem. The logic is pretty straightforward and can be modified to use different types of adaptive engines.
{Dynamic Moving AVerage System by George Pruitt} {Use volatility to adapt moving average lenghts} {in hopes to outperform a static parameter set!}
If average(c,shortMALen) crosses above average(c,longMALen) then buy next bar at open; If average(c,shortMALen) crosses below average(c,longMALen) then sellshort next bar at open;
Backtesting with [Trade Station,Python,AmiBroker, Excel]. Intended for informational and educational purposes only!
9237
Get All Four Books in the Easing Into EasyLanguage Series - The Day Trade Edition is now Available!
Announcement – A Day Trade Edition will be added to my Easing Into EasyLanguage Series this year! This edition will be the fourth installment and will utilize concepts discussed in the Hi-Res and Advanced Topics editions. I will show how to develop and program algorithms that will enter after the open of the day and get out before the market closes. Hence, no overnight exposure. Most examples will be carried out on the mini Dow, Nasdaq, S&P500 and Russel. The programming skills that you will learn can be carried to any market that provides enough bang for the buck to day trade. Look for this edition later this year. But get geared up for it by reading the first three editions in the series now. Get your favorite QUANT the books they need!
Hello to All! The Easing Into EasyLanguage Series is now complete with the publication of the Advanced Topics Edition. This series includes three educational editions. Start out with the Foundation Edition. It is designed for the new user of EasyLanguage or for those you would like to have a refresher course. There are 13 tutorials ranging from creating Strategies to PaintBars. Learn how to create your own functions or apply stops and profit objectives. Ever wanted to know how to find an inside day that is also a Narrow Range 7 (NR7?) Now you can, and the best part is you get over 4 HOURS OF VIDEO INSTRUCTION – one for each tutorial. All source code is available too, and if you have TradeStation, so are the workspaces. Plus you can always email George for any questions. george.p.pruitt@gmail.com.
This book is for those that have read the Foundation Edition or have some experience working with EasyLanguage and the various functions that help make a trading decision. This book’s audience will be those programmers that want to take an idea, that requires an observation of intraday market movements to make a trading decision, and program it accurately. If you have programmed daily bar systems, and you want to drill down and add some components that require additional market information (like what came first – the high or the low), then you have come to the right place. If you want to buy and sell short in the same day and use trade management principles such as profit targets and stop losses then The Hi-Res Edition is the book you need. There are two paradigms that EasyLanguage covers: daily and intraday bar programming. It’s the same language, but the move from daily to intraday programming can be quite difficult. Learn all the essentials and shortcuts with this edition. 5 HOURS OF VIDEO INSTRUCTION in this Hi-Res edition – one for each tutorial. All source code is available too, and if you have TradeStation, so are the workspaces. Plus you can always email George for any questions. george.p.pruitt@gmail.com.
Advanced Topics (AT) could cover a vast amount of ideas and concepts and be the length of “War and Peace” on steroids. Since this book is part of the series, I wanted to cover a handful of concepts that included the follow programming constructs. Arrays and their manipulation. Buffers (fixed length arrays) and the tools to maintain buffer elements with formulas for extraction and sorting. Finite State Machines using the switch-case construct and range based case values. Using original text graphic objects and retrieving and analyzing their properties to determine X and Y coordinate values of text location. Seasonality: The Ruggiero/Barna Universal Seasonal and the Sheldon Knight Seasonal methods. In AT, you will also find an introduction to EasyLanguage’s Project Concept and the steps to create one by adding/deleting component files. TradeStation now provides access to fundamental data such as Commitment of Traders – learn how to convert the Net Change indicator into a strategy utilizing the FundValue functionality. If you wanted to find out how to merge multiple time frames into a single indicator, you are in luck! Create a MTF indicator for yourself.
Day Trading (DT) – This is a surprise installment in my Easing into EasyLanguage Series, as I had only intended on three books. However, I think it will fit well with the other books. Daytrading is a very popular approach as overnight risk is eliminated. Don’t worry there is plenty of risk during the day too! However, it can be very difficult to accurately program a trading idea on higher resolution data such as five- or one-minute bars. Like my other books, there is no “Holy Grail” included. And if you are looking for a book that gets in and out of a trade in a few seconds, this is not the one for you. I discourage trading more than a handful of trades per day – this is best left up to the professionals. But, if you want to learn about volatility-based break outs, pyramiding, scaling out, zone-based trading, accurate trade accounting and having a peek at algorithms that once ruled the systematic daytrading industry, then this is the book for you. A beginner might have a little difficulty in following along with the tutorials. If you have read the first two books (Foundation and Hi-Res) in this series, you are good to go. Or if you have some experience working with EasyLanguage and minute data, you will be OK as well.
Pick up your copies today – e-Book or paperback format – at Amazon.com