This is the second part of the automated trading course, which will deal with how to write a profitable strategy. Some programming knowledge is required - for this, do the first part of the course if you haven't already. It's here:
The second part will cover writing basic trading strategies, trend and counter trend trading, optimizing, walk forward analysis, portfolio strategies, and money management. It uses some new trading algorithms such as frequency filters. To avoid misunderstandings: It's not a course about technical analysis. I won't explain here moving averages or the like. It's just about how to write a strategy based on a trading idea that you already have.
For the course you'll need a program for running the script examples and testing the strategies. It's called "Zorro" and you can download it for free - just google for "Zorro Trading Automaton". Please also download the latest patch from the Zorro user forum, as the release had a bug in the chart display.
Two things to keep in mind:
► All strategies presented in this thread are meant for educational purposes. They are all profitable, but designed for simplicity, not for maximum profit or robustness. For really trading such a strategy, you would normally add entry filter rules for filtering out unprofitable trades. How to find and generate such rules with machine learning algorithms, such as Zorro's perceptron or decision tree, might be covered in a future third part of the course. For really trading a strategy you normally also use a more sophisticated exit algorithm, realized with a trade management function. But that's also stuff for a future part and we'll keep it simple in this part of the course.
► I will post some backtest results here, but they can be slightly different to the results you'll get when testing the scripts yourself. That's because Zorro stores the current spread, commission, and rollover parameters for every asset when connecting to the broker. Because they change from time to time (and from broker to broker), backtest results also change. You can prevent this by setting Spread and other broker dependent parameters to a fixed value in the script, but keeping them in sync to the market gives a more realistic result.
Let's start. The point of trading is knowing the moment when it's good to buy, good to sell, or good to do nothing. Any trade strategy uses market inefficiencies - deviations of the price curves from random data - for predicting future prices and finding the right buying and selling points. The most obvious way to make profits is going with the trend. Let's have a little stage play in which trader Bob tries to explain his trade strategy to programmer Alice. Bob has just hired her to automatize his system:
Bob: I go with the trend. I buy long when prices start going up and I go short when they start going down.
Alice: And this works?
Bob: Sometimes. Depends on the market.
Alice: So you just buy long when today's price bar is higher than the bars of the previous days?
Bob: Nah, one higher price bar alone won't do. Prices wiggle a lot. Often the candles are all over the place. I look for the long term trend, like the trend of the last two months. I do that with a moving average.
Alice: Good. That shouldn't be a problem to automatize.
Bob: Well, actually there is a problem. You see, a two month moving average lags at least one month behind the price. Often the trend is already over when the average finally bends up or down. You need to sort of look ahead of the moving average curve, if you get my meaning.
Alice: So you want to know when a two months trend changes, but you need to know it in far less time than two months?
Bob: You got it.
Alice: I could use a lowpass filter for getting the trend curve. Second order lowpass filters have almost no lag. Will that be ok for you?
Bob: I dunno what a second order lowpass filter is. But I trust you.
Alice: Good. So I buy when the trend curve changes its direction? For instance, when it starts to move up from a valley, or down from a peak?
Bob: You got it.
Alice: How do you exit trades?
Bob: When it's the right time. Depends on the market.
Alice: I can exit a long position when entering a short one and vice versa. Does this make sense?
Bob: Yeah, that's what I normally do when I'm not stopped out earlier.
Alice: Stopped out?
Bob: Sure. A trade must be stopped when it's losing too much. We need a stop loss. Or do you want my whole account wiped from some bad trade?
Alice: Certainly not before I'm paid. At which price do you place the stop loss?
Bob: Not too far and not too tight. I don't want to lose too much, but I also don't want my trades stopped out all the time.
Alice: So let me guess: it depends on the market?
Bob: You got it.
Following the conversation, Alice wrote this trade strategy script for Bob, at a $5,000 fee:
code:function run()
{
var *Price = series(price());
var *Trend = series(LowPass(Price,1000));
Stop = 2*ATR(100);
if(valley(Trend))
enterLong();
else if(peak(Trend))
enterShort();
}
When you did the first part of the course, you might recognize some familar structures, such as the if statement, and some lines that look similar, but not quite like variable declarations. Tomorrow we'll go thoroughly over this script, analyze what it does line by line, and then look in detail into the behavior and performance of this strategy.
Let's start. The point of trading is knowing the moment when it's good to buy, good to sell, or good to do nothing. Any trade strategy uses market inefficiencies - deviations of the price curves from random data - for predicting future prices and finding the right buying and selling points. The most obvious way to make profits is going with the trend. Let's have a little stage play in which trader Bob tries to explain his trade strategy to programmer Alice. Bob has just hired her to automatize his system:
Bob: I go with the trend. I buy long when prices start going up and I go short when they start going down.
Alice: And this works?
Bob: Sometimes. Depends on the market.
Alice: So you just buy long when today's price bar is higher than the bars of the previous days?
Bob: Nah, one higher price bar alone won't do. Prices wiggle a lot. Often the candles are all over the place. I look for the long term trend, like the trend of the last two months. I do that with a moving average.
Alice: Good. That shouldn't be a problem to automatize.
Bob: Well, actually there is a problem. You see, a two month moving average lags at least one month behind the price. Often the trend is already over when the average finally bends up or down. You need to sort of look ahead of the moving average curve, if you get my meaning.
Alice: So you want to know when a two months trend changes, but you need to know it in far less time than two months?
Bob: You got it.
Alice: I could use a lowpass filter for getting the trend curve. Second order lowpass filters have almost no lag. Will that be ok for you?
Bob: I dunno what a second order lowpass filter is. But I trust you.
Alice: Good. So I buy when the trend curve changes its direction? For instance, when it starts to move up from a valley, or down from a peak?
Bob: You got it.
Alice: How do you exit trades?
Bob: When it's the right time. Depends on the market.
Alice: I can exit a long position when entering a short one and vice versa. Does this make sense?
Bob: Yeah, that's what I normally do when I'm not stopped out earlier.
Alice: Stopped out?
Bob: Sure. A trade must be stopped when it's losing too much. We need a stop loss. Or do you want my whole account wiped from some bad trade?
Alice: Certainly not before I'm paid. At which price do you place the stop loss?
Bob: Not too far and not too tight. I don't want to lose too much, but I also don't want my trades stopped out all the time.
Alice: So let me guess: it depends on the market?
Bob: You got it.
Following the conversation, Alice wrote this trade strategy script for Bob, at a $5,000 fee:
code:function run()
{
var *Price = series(price());
var *Trend = series(LowPass(Price,1000));
Stop = 2*ATR(100);
if(valley(Trend))
enterLong();
else if(peak(Trend))
enterShort();
}
When you did the first part of the course, you might recognize some familar structures, such as the if statement, and some lines that look similar, but not quite like variable declarations. Tomorrow we'll go thoroughly over this script, analyze what it does line by line, and then look in detail into the behavior and performance of this strategy.
I've seen some of this stuff before...where is it plagiarised from?
We're going to analyze the trading code. At first, we can see that the function is now named "run" and not "main". "run" is also a special function name, but while a main function runs only once, a run function is called after every bar with the period and asset selected with the scrollbars. By default, the bar period is 60 minutes. So this function runs once per hour when Zorro trades.
At the begin we notice two strange lines that look similar to var definitions:
var *Price = series(price());
var *Trend = series(LowPass(Price,1000));
However unlike var definitions, they have an asterisk '*' before the name, and are set to the return value of a series() function call. We define not a single variable here, but a whole series. (C++ programmers might notice that we in fact define a pointer, but that needs not bother us now). A series is a variable with a history - the series begins with the current variable value, then comes the value the variable had one bar before, then the value from two bars before and so on. This is mostly used for price curves and their derivatives. For instance, we could use a series to take the current price of an asset, compare it with the price from 1 bar before, and do some other things dependent on past prices. The series is the ideal construct for such price calculations.
The current value of a series can be used by adding a [0] to the series name; for the value from one bar before add a [1], for two bars before add a [2] and so on. So, in Alice's code Price[0] would be the current value of the Price series, and Price[1] the value from 1 hour ago. Many trade platform languages - for instance, EasyLanguage - support series this way; usually indicator, statistics, and financial functions all use series instead of single variables. We'll encounter series very often in trade scripts and will become familiar with them.
The series() function can be used to convert a single variable to a series. The variable or value for filling the series is normally passed to that function. However, we're not using a variable here, but the return value of a function call. var *Price = series(price()); means: define a var series with the name "Price" and fill it with the return value of the price() function. We've learned in the last programming lesson how to 'nest' function calls this way, passing the return values of functions as parameters to other functions.
The price() function returns the mean price of the selected asset at the current bar. There are also priceOpen(), priceClose(), priceHigh() and priceLow() functions that return the open, close, maximum and minimum price of the bar; however, the mean price is usually the best for trend trading strategies. It's averaged over all prices inside the bar and thus generates a smoother price curve.
var *Trend = series(LowPass(Price,1000));
The next line defines a series named "Trend" and fills it with the return value from the LowPass function. As you probably guessed, this function is Alice's second order lowpass filter. Its parameters are the previously defined Price series and a time period, which Alice has set to 1000 bars. 1000 bars are about 2 months (1 week = 24*5 = 120 hours). Thus the lowpass filter attenuates all the wiggles and jaggies of the Price series that are shorter than 2 months, but it does not affect the trend or long-term cycles above two months. It has a similar smoothing effect as a Moving Average function, but has the advantages of a better reproduction of the price curve and less lag. This means the return value of a lowpass filter function isn't as delayed as the return value of a Moving Average function that is normally used for trend trading. The script can react faster on price changes, and thus generate better profit.
The next line places a stop loss limit:
Stop = 2*ATR(100);
Stop is a predefined variable that Zorro knows already, so we don't have to define it. It's the maximum allowed loss of the trade; the position is sold immediately when it lost more than the given value. The limit here is given by 2*ATR(100). The ATR function is a standard indicator. It returns the Average Price Range - meaning the average height of a candle - within a certain number of bars, here the last 100 bars. So the position is sold when the loss exceeds two times the average candle height of the last 100 bars. By setting Stop not at a fixed value, but at a value dependent on the fluctuation of the price, Alice adapts the stop loss to the market situation. When the price fluctuates a lot, higher losses are allowed. Otherwise trades would be stopped out too early when the price jumps down just for a moment.
A stop loss should be used in all trade strategies. It not only limits losses, it also allows Zorro's trade engine to better calculate the risk per trade and generate a more accurate performance analysis.
The valley function is a boolean function; it returns either true or false. It returns true when the series just had a downwards peak. The peak function returns true when it just had an upwards peak. When the if(..) condition becomes true, a long or short trade with the selected asset is entered with a enterLong or enterShort command. If a trade was already open in the opposite direction, it is automatically closed. Note how we combined the else of the first if with a second if; the second if() statement is only executed when the first one was not.
Let's have a look into an example trade triggered by this command:
The red line in the chart above is the Trend series. You can see that it has a peak at the end of September 2008, so the peak(Trend) function returned true and the enterShort function was called. The tiny green dot is the moment where a short trade was entered. The Trend series continues downwards all the way until November 23, when a valley was reached. A long trade (not shown in this chart) was now entered and the short trade was automatically closed. The green line connects the entry and exit points of the trade. It was open almost 2 months, and made a profit of ~ 13 cents per unit, or 1300 pips.
In the next lesson we'll learn how to backtest such a strategy and how to judge its profitability. There were a lot new concepts in this lesson, so please ask here if something is unclear or could be better explained.
I've seen some of this stuff before...where is it plagiarised from?
Pardo's book reads like this, but I don't think this post is plagiarism.
In Pardo's book, they have a dialogue between a trader and a programmer. The trader is all like:
Trader: Do this magic shit I came up with out of my ass
Programmer: Define magic shit
Trader: Hey stupid, I'm paying you to come up with that
Programmer: I graduated from school last week man, you're paying me in nothing but hopes, dreams, and inspirational posts on ET.