Thanks a lot, R. I will try it out today. What do you think? Last edited: Sep 22, Romeo Well-Known Member Sep 22, Thanks for all the help, R! Select data source: TradingView. Local data storage: Enable. Enter the number of bars. Set base time interval. Press Ok. In some cases there can be timing issues if you do not set precisely the Extended Time Shift in the plugin's configuration dialog Not the Time Shift in the database settings dialog! This can happen when chart data is imported from some "special" markets.
Markets in the East. In this case the first and last data bars coming from the same trading session will fall on another day. The same problem appears when the session time is, for example, - Do not forget to indicate the serial number - displayed by the demo plugin - during the payment!
Please read the FAQ for details. Search this site. Click Here to Download Demo v5. SymbolInfo files only. Tutorial Videos. Markets in the East E. You can find your serial number here. Report abuse. Google Sites.
In this article, we take a look at how to debug strategy afls in AmiBroker. As most of our automated trading users in India are using free trial version of AmiBroker which does not have debugging feature enabled; we explain a very basic mechanism of debugging. The demo is available on YouTube. AutoTrader api provides a chart parameter, which can be set ON to print additional logs. See below:. Just a signal appearing in your chart does not mean order will be fired.
In fact, a signal on the chart has nothing to do with an order being fired. Here is an example of how the logs look:. This will help you understand the strategy execution flow. Your if condition is not evaluating to true , when you expect it to be true. Here is an example of how to do that:. Now see the logs, this will tell you that the result is not true when you expect it to be.
Look at the AutoTrader Support notes or email support. Once an order is placed from AmiBroker, then after that point it is responsibility of AutoTrader to place that order onto trading platform. Here is an example:. Additionally you can use these order ids to look at AutoTrader logs. The number 2 signifies that the trade exit will be placed on the next bar.
If we were to use 1, then the trade exit would occur at the trade price intraday. There are different ways to set up the ApplyStop settings as shown in this article. When using end-of-day data you generally want to specify either the open price or the close price. If trading intraday then you can set up a limit price of your choice:.
When you write your entry rules in Amibroker you may end up with more than one candidate and so you need a way to choose between them. For this, Amibroker includes a variable PositionScore which allows you to rank all the stocks that meet your rules. PositionScore tells Amibroker to choose the highest scoring symbols first. It will then choose the higest scoring candidates. Alternatively, you can ask Amibroker to choose the lowest scores first by substracting from or inverting the formula.
For example, the following formula will now pick the lowest RSI 14 scores first:. Putting all the above code together gives us a very simple Amibroker trading system. Now the formula has been loaded into the Analysis Window you can set the dates you want to test and the symbols by clicking on the green funnel icon. Then hit Backtest and the backtest will run. A useful feature of Amibroker is being able to clearly see every trade taken by the backtester in the Result List.
This tab is found at the bottom of the screen while in the Analysis Tab. This is the first thing you should look at to make sure that the backtest is actually doing what you expect it to do. Once you are in the Result List tab you can right click on any trade and click show current trade arrows. That action will place trade arrows into the price chart window.
You can then go back to the chart and see if the trades are taking place at the right times. Once you are satisfied that the system is doing as you expect it you can move on to the detailed backtest report. This report shows you numerous statistics as well as equity curves, drawdown charts, profit tables and monte carlo runs:. An optimization lets you backtest many different settings at once. For example, instead of running one backtest using a day moving average, you could run 10 backtests at once analysing every moving average length from days to days.
By testing a broad range of variables you will typically find a sweet spot where your system works best. You can then drill further down into this sweet spot to find the best performing parameters. Robust parameters are those that are based on a large sample of trades and which are surrounded by similar strong performing parameters.
For example, the following graphic shows a basic optimization report for a moving average crossover test. The graphic shows that there are many different combinations of moving average that produce resonable results. However, there is a definite sweet spot of performance which I have circled in white. Values in this range are more likely to be robust since the performance is more consistent within this range of values.
To run an optimization in Amibroker we can create a new identifier in our AFL code and then instruct Amibroker to optimize the parameters. Using the formula below as an example, the optimization starts at a day moving average, it then tests every moving average length up to in steps of The figure is the default moving average that will be applied if an optimization is not run.
For example, if you run a backtest and no optimization:. In other words, this code enables us to test every moving average length from 50 to in steps of The more variables and steps involved in the optimization, the longer the optimization will take. The code below optimizes three different variables, fast moving average, slow moving average and stop loss. Amibroker will test every combination of the three settings above. The speed of the optimization will depend on the power of your computer and the number of stocks being tested on.
These techniques speed up the optimization procedure by focussing on the steps of the optimization that are most likely to be useful. For example, once the algorithm finds a setting that is optimal it may skip all nearby steps greatly speeding up the process.
Optimization is a fast and powerful tool. As mentioned, its important not to over-optimize but to use optimization to find robust patterns and market truths. Walk forward analysis is another powerful feature for trading system developers. Other platforms seem to find this technique difficult but in Amibroker it is a breeze. The idea of a walk forward optimisation is to optimise your system on some in-sample data, then test it on out-of-sample data, using the best parameters that were found in-sample.
You then move forward and do it again, until you have reached the end of the data. Next, you concatenate stitch together all of the out-of-sample segments to get a performance summary that consists only of the out-of-sample parts. This is a great way to produce less biased backtest results since you are building a system based only on the out-of-sample results. Using a walk forward method is similar to how you might approach real trading.
You have an idea of what works and then you go and trade it in the live market. Using a walk forward analysis you can get an idea of what would happen if you did that. First by optimizing the search and then by validating it repeatedly on different segments of out-of-sample data. To run a walk forward analysis you first set up an optimization, just like we did earlier. You then need to adjust some items in the backtest settings on the Walk Forward tab.
You will need to set your in-sample and out-of-sample dates and select the optimization target. The optimization target tells Amibroker which metric to benchmark performance by. For example, do you want to select the strategy that makes the most profit or the smallest drawdown? For a walk-forward analysis to be effective you need to use enough data in the in-sample period to give you a large enough sample of trades.
You can then use an out of sample that is maybe a third the size of the in sample. For example, I might use an in-sample period that lasts five years and generates 1, trades then use a walk-forward sample of two years.
Essentially you are optimising the system over 5 years of data, then you take the best variation of the system and backtest it on the next two years of unseen data. The process steps forward and we do it again. The optimisation target can be altered to anything you like. Once the walk forward is done Amibroker is going to stitch together all of the out-of-sample segments. If you want to learn Amibroker and learn how to build good strategies, walk-forward analysis is a powerful tool.
You can take a semi automated or fully automated approach depending on your programming skill and confidence level. With a semi automated approach you let Amibroker do most of the heavy lifting. You use it to run the explorations and calculate the entry orders. However, you execute the trades manually by placing them directly into your brokerage account. This is the method I follow because I like to retain some control over my trades. Alternatively, Amibroker has all the functionality to link directly with Interactive Brokers using the Amiboker IB controller.
The IB controller is a piece of software that connects to TWS and is able to accepts orders and commands from Amibroker. This approach allows full automation, however, it does require a high level of Amibroker programming skill. A final alternative is to use thirdy party software to link Amibroker with Interactive Brokers.
This is approach requires additional software but is a less complicated process than using the IB controller. I go into this in more detail in this post on automation with Amibroker. Backtesting, optimization and walk forward analysis are powerful tools for traders. Curve fitting occurs when you over-optimize on your data.
You create a strategy that performs exceptionally on your in-sample data but is unlikely to perform well on unseen data. The goal of a backtest is to find market truths, robust strategies that you are confident will work in the future. It was developed specifically by Tomasz Janecsko to make anlaysing financial data efficient and fast. In this section of our Amibroker tutorial we will look more closely at how arrays work.
An array is a container that holds a fixed number of values of a single type. The way I understand arrays is that an array is simply a list of data. But instead of this list going down the page it goes across. So an array is a row of data similar to what you might see on a typical Excel spreadsheet. When you set up a database, Amibroker stores 6 arrays for each symbol.
Each value that is stored in one of these arrays represents one bar, or one period of time essentially. You import these arrays directly into Amibroker in the correct format such as from a CSV file. Amibroker then creates new arrays to calculate any formulas within the code itself. Amibroker reads the data, runs calculations and can present it in a chart. The very first number in the array in your list of data is going to be the first bar on your chart.
The last number in the array will be the most recent bar on the chart. If you think of an array as a list of values that is ordered by date and then laid out on a horizontal time line with the first number in the list being the oldest and the last value being the newest. The first 6 arrays are default Amibroker arrays for the open, high, low, close, volume and open interest. Each cell in the array represents one bar. The first bar in the array is given an index value of zero. Every other bar now has its own index value in relation to this first bar.
This is just an example formula that we created in the AFL. For example, the close price on the very first bar is written as Close while the close price on day five is close and the close price 10 bars along is Close. An important distinction is that these are unique values.
When we use square brackets we are referencing individual numbers not arrays. In other words, not the whole lines of the data. It refers to the value of the close for each bar in the array. Amibroker also provides a function called Ref. This tells Amibroker to create a new array referencing a future or historical bar.
For example, Ref Close, -3 will create a new array that stores the close price from 3 bars prior. Instead, by creating arrays it can perform calculations in just one stage. The first example is looking at a precise point in the data while the second is calculating the result on a bar by bar basis, so the result is an array. This second type is generally whats used when running backtests and doing analysis. The ability to simplify calculations like this is what makes Amibroker fast. Every bar, Amibroker is going to run a calculation to see if the close is above the open and then give us a true or a false.
The IIF function can be used to return a value that is different from true or false. You can then use the result from this formula in another place. Perhaps lower down in your trading system code. Now UpClose is its own array. It contains either the close or the open, on a bar by bar basis, depending on whether the bar is an up day or down day.
Obviously you can do all sorts of more complex calculations with this. A trick for progamming Amibroker AFL code in the beginning is to start off with a spreadsheet. Lay all the data out in rows so you can get an idea for how Amibroker looks at the data and does its calculations. For example, set up 10 columns in Excel, with 6 rows; open, high, low, close, volume and open interest. Underneath these, you can set up additional rows to store your calculations.
Often you can do the calculations you need with simple math. Always check the amibroker function reference as it provides lots of pre-built functions to speed up your workflow. When you really get to grips with Amibroker you can get into more advanced stuff like the custom backtester which allows you to take full control of the Amibroker backtest engine.
For the most part though, you can do most of what you need without getting too deep. The beauty of arrays and in-built functions is that many sophisticated formulas can be written in just a few lines of code. One of the most important things to remember when you learn Amibroker is that there is always more than one way to do something in Amibroker. Work out what you need on a piece of paper first.
You can use a spreadsheet as a tool to work through your steps. For example Min Close,Open is going to return the smallest of either the close or open price. If it was Max it would return the highest of those two arrays. This is how you might start to code a breakout system. Sum can be used to sum all of the values over the last n number of bars.
For example Sum H,10 is going to add up all of the last 10 highs together. You can use that result in another formula. Cum is the cumulative sum of the values in an array since the very beginning of the array. This can be used to add up events. For example you can count the number of times the close has finished higher than the open since the very first bar. LastValue gives the final value in an array. This is useful if you want to tell Amibroker to exit a stock on the very last bar.
For example if it gets delisted. Ref is used to reference previous or future bars. So if you think back to the concept of data laid out like in a spreadsheet and use the ref function to either step back or forward along each bar. BarsSince ; returns the number of bars since the array returned true.
MA is a simple moving average, so to write a 50 period moving average of the close you simply write MA C, This also means you can calculate a moving average of any array you like. For example MA H,50 calculates a moving average, not of the close, but of the last 50 high prices. EMA is the exponential moving average and is written just like the simple moving average. You can see which moving average works best here. RSI is the relative strength index, which is a popular momentum oscillator.
It is often used in mean reversion strategies too. MFI is the money flow indicator which is a similar indicator to RSI but also takes volume into consideration. ROC gives the rate of change, which is simply the percentage change over n number of bars.
Percentile is quite useful and can be used to return the rank percentile value of an array. It will simply assign the value of 70 to the RSIValue variable. What you really want to do is use:. Another way you might do this is by using the NOT function. For a full list of operators see the Amibroker reference manual. A classic example of this is when your system trades on the open, but it relies on an indicator for example the RSI that uses the close price.
The system is buying on the open but the indicator is calculated with the close. In this instance you might want to use SetTradeDelays to delay your entry to the next bar open. Look forward errors like this can sometime be sneaky and hard to spot so caution is needed. Always remeber, if your results look too good to be true there could be some issue like future leak somewhere in the code. Similar to the future error mistake you must make sure your system uses realistic entry and exit prices.
Sometimes, you can get a situation where you get a trading signal but execute an unrealistic price entry. For example, when using limit orders. However, when using adusted stock data this type of limit price might cause an issue. Sometimes Amibroker might trade on the exact low of the day giving very little margin for error. This may be an unlikely price fill especially if the data is adjusted. It also ignores your market impact on the bid:ask spread. This introduces some more realistic slippage to the entry price to make sure that your entry would have been filled in real trading:.
However, we make sure that the low of the day is at least 0. This provides some margin of safety and ensures that the backtest enters a realistic price fill. These are some of the questions that need to be addressed when choosing a data provider and before backesting. If you use data that is not adjusted for stock splits, then there will be many price gaps to be aware of.
This might be OK if you trade intraday but it is not going to provide accurate backtest results for longer-term strategies. Data that is not adjusted for dividends will likely lead to underperformance in the backtest. However, data that is adjusted could lead to erroneous entry signals since the price is adjusted and not the actual price. The right approach is to test strategies on both types of data. Data also needs to include delisted stocks and historical members.
Stocks are removed from the exchange all the time and backtesting without these securities leads to survivorship-bias and distorted results. If the data is daily be aware that testing intraday price fills is likely to be unrealistic. Intraday systems typically need 1-minute data or less to provide accurate simulations. When using fundamental data be aware of the many adjustments and accounting discrepancies that can occur after the fact.
For example, the Fed may release an unemployment number and later adjust it to something else when they have more data. For an accurate backtest, you need to have the initial data point and not the adjustment. Likewise, a data point might have a published date and a reported date. The reported date might be when the event actually took place and the published date is when it became public information. Another mistake can occur when Amibroker holds a trade open in a delisted security.
Typically, you want to exit any stock that has been delisted or merged with another company. If you see that your backtest results only has a small number of trades and a lot of open positions then check to see whether any of them are delisted stocks. The following code uses BarIndex to force close positions on the last bar in the database:. If you use a third party database like Norgate Data then you may want to refer to the delisting date which has already been set for each delisted security in the database:.
Finally, make sure any system you create is not buying an unrealistic amount of stock.
Ref - reference past/future values of the array ; SYNTAX, Ref(ARRAY, period) ; RETURNS, ARRAY ; FUNCTION, References a previous or subsequent element in a ARRAY. The LastValue function turns the resulting array value into a scalar PriceVolDistricution needs as an input, eg: NewDay = Day()!. expandLast - the compressed value is expanded starting from last bar within given period (so for example weekly close/high/low is available on Friday's bar).