User-defined bars
Instead of fixed bar periods, bars can also cover fixed price ranges or can be defined by other criteria.
Some traders believe that those special bars help their trading, because they
make the chart look simpler. Zorro supports a user-defined bar function
for special bars of any kind. Predefined functions for Range, Renko, Haiken Ashi, or
Point-and-Figure bars are included. The bar function can be used for single-asset or multiple-asset
strategies, or for strategies that use multiple bar types simultaneously. In the
case of single-asset strategies the individual bars are also plotted in the
chart.

Range bars (see code)
bar(vars Open, vars High, vars Low, vars Close, vars Price, DATE Start, DATE Time): int
User-supplied function for defining a bar. Used to create special bar types or to replace the mean price by a different algorithm. The
bar function is automatically called whenever a new price quote arrives or a price tick is read from a historical file. It can modify the candle and determine when the bar ends.
Parameters:
Open, High,
Low, Close, Price |
Series with two elements of the corresponding price; e.g., Close[1] is the close price of the previous bar, and Close[0] is the most recent price. The prices of the current bar can be modified by the bar function. Price is the mean price and can be omitted when not used in the function.
|
Start |
Optional start time of the bar in the OLE DATE format. Can be omitted when not used in the function. |
Time |
Optional time of the most recent tick or price quote. Can be omitted when not used in the function. |
Returns:
0 - close the bar at the normal end of the BarPeriod.
1 - close the bar now, and call the bar function again at the next price tick.
4 - keep the bar open, and call the bar function again at the next price tick.
8 - call the bar function only at the end of every bar.
Remarks:
- The bar function in a single asset strategy is
automatically called during the history building process and has access to the current and previous candle. Indicators, series, price, or trade functions cannot be called from inside a bar function.
If needed for a very special bar, calculate the candle in the
run function and pass it to the bar
function through global variables.
- If prices are not otherwise modified by the bar function, they are set up as for a normal candle, i.e., Open[0] is the first price of the bar, High[0] is the highest price so far, Low[0] the lowest price and Price[0] the current mean price of the bar.
- Modified prices also determine the corresponding price functions (priceO, priceH, priceL, priceC, price)
and all price-dependent indicators. This can cause
data-snooping and therefore unrealistic
backtests when the bar open price is affected by its close price
or by the high or low.
Backtest with the TICKS flag for making sure
that the trades open and close at the recent tick instead of the back
candle, thus eliminating snooping bias.
- Set Slippage = 0 for backtests with
user defined bars. Slippage simulation works only with normal bars.
- The price history should have sufficient
resolution so that any special bar covers at least one price
quote. Special bars cannot have higher resolution than the price
history.
- Most special bars, such as Haiken Ashi or Range/Renko bars, are
affected by any preceding bar and thus
depend on the time stamp or price at the very
first bar. Their candles therefore depend on start date, lookback period, bar period, bar
offset, time zone, or any other settings that affect the first bar.
- BarPeriod has
no effect on range dependent bars except for the above mentioned start time and the pre-allocation
of bar memory. For allocating enough bars without wasting memory,
set BarPeriod to the approximate average bar
duration that is displayed in the
performance report. If you don't know
it, set
BarPeriod = 1. Bar zones and bar offsets should not be set when using special bar types.
- In multi-asset strategies, or in strategies with multiple bar
types, the bar defining function must be called in the script
individually per asset or algo, and thus
needs a different name than bar for not being
called automatically. Since any asset has different bars,
series must be static and shifted by script.
An example for a multiple asset strategy with Renko bars can be
found in the SpecialBars script.
- Renko bars are described slightly differently on different websites.
The examples below contain 3 known variants.
- Traditional price-distance bars, such as Renko, Range, or
Point-and-Figure bars, are not
really recommended for serious trading systems, since they
ignore the time component and have normally a negative effect
on the performance.
This may be different for special bars sampled by other criteria
such as trade volume or tick rate. Experiment with your own bar types!
Examples (see also SpecialBars.c):
var BarRange = 0.0030; // 0.3 cents bar range
// Range Bars, standard (high-low)
int bar(vars Open,vars High,vars Low,vars Close)
{
if(Open[0] != Close[1]) {
High[0] = max(Open[0],Close[1]);
Low[0] = min(Open[0],Close[1]);
Open[0] = Close[1];
}
if(High[0]-Low[0] >= BarRange)
return 1;
return 4;
}
// Renko Bars, standard
int bar(vars Open,vars High,vars Low,vars Close)
{
Open[0] = roundto(Close[1],BarRange);
if(Close[0]-Open[0] >= BarRange) {
Close[0] = Open[0]+BarRange;
High[0] = Close[0];
Low[0] = Open[0];
return 1;
}
if(Open[0]-Close[0] >= BarRange) {
Close[0] = Open[0]-BarRange;
High[0] = Open[0];
Low[0] = Close[0];
return 1;
}
return 4;
}
// Renko Bars with wicks
int bar(vars Open,vars High,vars Low,vars Close)
{
Open[0] = roundto(Close[1],BarRange);
if(Close[0]-Open[0] >= BarRange) {
Close[0] = Open[0]+BarRange;
return 1;
}
if(Close[0]-Open[0] <= -BarRange) {
Close[0] = Open[0]-BarRange;
return 1;
}
return 4;
}
// Renko Bars, variant
int bar(vars Open, vars High, vars Low, vars Close)
{
var OpenDiff = abs(Close[0]-Open[1]);
var CloseDiff = abs(Close[0]-Close[1]);
if(OpenDiff < CloseDiff) // we have a valley or peak
Open[0] = Open[1];
else // we are moving with the trend
Open[0] = roundto(Close[1],BarRange);
if(Close[0]-Open[0] >= BarRange) { // going up
Close[0] = Open[0]+BarRange;
High[0] = Close[0];
Low[0] = Open[0];
return 1;
}
if(Open[0]-Close[0] >= BarRange) { // going down
Close[0] = Open[0]-BarRange;
High[0] = Open[0];
Low[0] = Close[0];
return 1;
}
return 4;
}
// Mean Renko Bars
int bar(vars Open, vars High, vars Low, vars Close) { Open[0] = 0.5*(Close[1]+Open[1]); if(Close[0] <= Open[0] - BarRange) { Close[0] = Open[0] - BarRange; return 1; } else if(Close[0] >= Open[0] + BarRange) { Close[0] = Open[0] + BarRange; return 1; } return 4; }
// Haiken Ashi Bars
int bar(vars Open,vars High,vars Low,vars Close)
{
Close[0] = (Open[0]+High[0]+Low[0]+Close[0])/4;
Open[0] = (Open[1]+Close[1])/2;
High[0] = max(High[0],max(Open[0],Close[0]));
Low[0] = min(Low[0],min(Open[0],Close[0]));
return 8;
}
// Point-and-Figure Bars
int bar(vars Open,vars High,vars Low,vars Close)
{
static int direction = 0;
if(direction == 1 && High[0]-Close[0] >= BarRange) {
Open[0] = round(Low[0],BarRange);
Close[0] = round(High[0],BarRange);
Low[0] = Open[0];
High[0] = Close[0];
direction = 0;
return 1;
}
if(direction == 0 && Close[0]-Low[0] >= BarRange) {
Open[0] = round(High[0],BarRange);
Close[0] = round(Low[0],BarRange);
High[0] = Open[0];
Low[0] = Close[0];
direction = 1;
return 1;
}
return 4;
}
See also:
Bars and Candles, Bar, BarPeriod, tick, TMF, user supplied functions
► latest
version online
|
Benutzerdefinierte Balken
Statt fester Balkenperioden können Balken auch feste Preisbereiche abdecken oder nach anderen Kriterien definiert werden.
Einige Händler glauben, dass diese speziellen Balken ihrem Handel helfen, weil sie
das Diagramm einfacher aussehen lassen. Zorro unterstützt eine benutzerdefinierte bar-Funktion
für spezielle Balken jeglicher Art. Vorgefertigte Funktionen für Range, Renko, Haiken Ashi oder
Point-and-Figure-Balken sind enthalten. Die bar-Funktion kann für Einzel- oder Mehrasset-
Strategien verwendet werden, oder für Strategien, die gleichzeitig mehrere Balkentypen nutzen. Im
Falle von Einzelasset-Strategien werden die einzelnen Balken auch im
Diagramm dargestellt.

Range-Balken (siehe Code)
bar(vars Open, vars High, vars Low, vars Close, vars Price, DATE Start, DATE Time): int
Vom Benutzer bereitgestellte Funktion zur Definition eines Balkens. Wird verwendet, um spezielle Balkentypen zu erstellen oder den Durchschnittspreis durch einen anderen Algorithmus zu ersetzen. Die
bar-Funktion wird automatisch aufgerufen, wenn ein neues Preisangebot eintrifft oder ein Preis-Tick aus einer historischen Datei gelesen wird. Sie kann die Kerze modifizieren und bestimmen, wann der Balken endet.
Parameter:
Open, High,
Low, Close, Price |
Serien mit zwei Elementen des entsprechenden Preises; z.B. Close[1] ist der Schlusskurs des vorherigen Balkens und Close[0] ist der aktuellste Preis. Die Preise des aktuellen Balkens können von der bar-Funktion modifiziert werden. Price ist der Durchschnittspreis und kann weggelassen werden, wenn er in der Funktion nicht verwendet wird.
|
Start |
Optionale Startzeit des Balkens im OLE DATE-Format. Kann weggelassen werden, wenn sie in der Funktion nicht verwendet wird. |
Time |
Optionale Zeit des jüngsten Ticks oder Preisangebots. Kann weggelassen werden, wenn sie in der Funktion nicht verwendet wird. |
Rückgaben:
0 - den Balken am normalen Ende der BarPeriod schließen.
1 - den Balken jetzt schließen und die bar-Funktion beim nächsten Preis-Tick erneut aufrufen.
4 - den Balken offen halten und die bar-Funktion beim nächsten Preis-Tick erneut aufrufen.
8 - die bar-Funktion nur am Ende jedes Balkens aufrufen.
Bemerkungen:
- Die bar-Funktion in einer Einzelasset-Strategie wird
automatisch während des History-Building-Prozesses aufgerufen und hat Zugriff auf die aktuelle und vorherige Kerze. Indikatoren, Serien, Preise oder Handelsfunktionen können nicht innerhalb einer bar-Funktion aufgerufen werden.
Falls für einen sehr speziellen Balken benötigt, berechne die Kerze in der
run-Funktion und übergebe sie der bar-Funktion über globale Variablen.
- Wenn Preise nicht anderweitig von der bar-Funktion modifiziert werden, werden sie wie bei einer normalen Kerze eingerichtet, d.h. Open[0] ist der erste Preis des Balkens, High[0] ist der bisher höchste Preis, Low[0] der niedrigste Preis und Price[0] der aktuelle Durchschnittspreis des Balkens.
- Modifizierte Preise bestimmen auch die entsprechenden Preisfunktionen (priceO, priceH, priceL, priceC, price)
und alle preisabhängigen Indikatoren. Dies kann
Data-Snooping verursachen und daher unrealistische
Backtests, wenn der Eröffnungspreis des Balkens durch seinen Schlusskurs
oder durch das Hoch oder Tief beeinflusst wird.
Führe Backtests mit dem TICKS-Flag durch, um sicherzustellen,
dass die Trades am jüngsten Tick und nicht an der vorherigen Kerze eröffnet und geschlossen werden, wodurch Snooping-Bias eliminiert wird.
- Setze Slippage = 0 für Backtests mit
benutzerdefinierten Balken. Die Slippage-Simulation funktioniert nur mit normalen Balken.
- Die Preis-Historie sollte eine ausreichende Auflösung haben, damit jeder spezielle Balken mindestens ein Preisangebot abdeckt. Spezielle Balken können keine höhere Auflösung haben als die Preis-Historie.
- Die meisten speziellen Balken, wie Haiken Ashi oder Range/Renko-Balken, werden
von jedem vorhergehenden Balken beeinflusst und hängen daher
vom Zeitstempel oder Preis des allerersten Balkens ab. Ihre Kerzen hängen daher von Startdatum, Rückblickperiode, Balkenperiode, Balkenoffset, Zeitzone oder anderen Einstellungen ab, die den ersten Balken beeinflussen.
- BarPeriod hat
keinen Effekt auf rangeabhängige Balken außer der oben genannten Startzeit und der Vorallokation
des Balkenspeichers. Um genügend Balken ohne Speicherverschwendung zuzuweisen,
setze BarPeriod auf die ungefähre durchschnittliche Balkendauer, die im
Leistungsbericht angezeigt wird. Wenn du sie nicht kennst, setze
BarPeriod = 1. Balkenzonen und Balkenoffsets sollten nicht gesetzt werden, wenn spezielle Balkentypen verwendet werden.
- In Mehrasset-Strategien oder in Strategien mit mehreren Balkentypen muss die Balkendefinierfunktion im Skript
individuell pro Asset oder Algo aufgerufen werden und benötigt daher
einen anderen Namen als bar, um nicht automatisch aufgerufen zu werden. Da jedes Asset unterschiedliche Balken hat,
müssen Serien statisch sein und durch das Skript verschoben werden.
Ein Beispiel für eine Mehrasset-Strategie mit Renko-Balken findet sich im
SpecialBars-Skript.
- Renko-Balken werden auf verschiedenen Websites leicht unterschiedlich beschrieben.
Die unten stehenden Beispiele enthalten 3 bekannte Varianten.
- Traditionelle preisabstandsabhängige Balken, wie Renko, Range oder
Point-and-Figure-Balken, werden für ernsthafte Handelssysteme nicht
wirklich empfohlen, da sie die Zeitkomponente ignorieren und normalerweise eine negative Auswirkung
auf die Performance haben.
Dies kann für spezielle Balken, die nach anderen Kriterien wie Handelsvolumen oder Tickrate abgetastet werden, anders sein. Experimentiere mit deinen eigenen Balkentypen!
Beispiele (siehe auch SpecialBars.c):
var BarRange = 0.0030; // 0.3 Cent Balkenbereich
// Range-Balken, Standard (Hoch-Tief)
int bar(vars Open,vars High,vars Low,vars Close)
{
if(Open[0] != Close[1]) {
High[0] = max(Open[0],Close[1]);
Low[0] = min(Open[0],Close[1]);
Open[0] = Close[1];
}
if(High[0]-Low[0] >= BarRange)
return 1;
return 4;
}
// Renko-Balken, Standard
int bar(vars Open,vars High,vars Low,vars Close)
{
Open[0] = roundto(Close[1],BarRange);
if(Close[0]-Open[0] >= BarRange) {
Close[0] = Open[0]+BarRange;
High[0] = Close[0];
Low[0] = Open[0];
return 1;
}
if(Open[0]-Close[0] >= BarRange) {
Close[0] = Open[0]-BarRange;
High[0] = Open[0];
Low[0] = Close[0];
return 1;
}
return 4;
}
// Renko-Balken mit Dochten
int bar(vars Open,vars High,vars Low,vars Close)
{
Open[0] = roundto(Close[1],BarRange);
if(Close[0]-Open[0] >= BarRange) {
Close[0] = Open[0]+BarRange;
return 1;
}
if(Close[0]-Open[0] <= -BarRange) {
Close[0] = Open[0]-BarRange;
return 1;
}
return 4;
}
// Renko-Balken, Variante
int bar(vars Open, vars High, vars Low, vars Close)
{
var OpenDiff = abs(Close[0]-Open[1]);
var CloseDiff = abs(Close[0]-Close[1]);
if(OpenDiff < CloseDiff) // wir haben ein Tal oder einen Gipfel
Open[0] = Open[1];
else // wir bewegen uns mit dem Trend
Open[0] = roundto(Close[1],BarRange);
if(Close[0]-Open[0] >= BarRange) { // Aufwärtstrend
Close[0] = Open[0]+BarRange;
High[0] = Close[0];
Low[0] = Open[0];
return 1;
}
if(Open[0]-Close[0] >= BarRange) { // Abwärtstrend
Close[0] = Open[0]-BarRange;
High[0] = Open[0];
Low[0] = Close[0];
return 1;
}
return 4;
}
// Mean Renko-Balken
int bar(vars Open, vars High, vars Low, vars Close) { Open[0] = 0.5*(Close[1]+Open[1]); if(Close[0] <= Open[0] - BarRange) { Close[0] = Open[0] - BarRange; return 1; } else if(Close[0] >= Open[0] + BarRange) { Close[0] = Open[0] + BarRange; return 1; } return 4; }
// Haiken Ashi-Balken
int bar(vars Open,vars High,vars Low,vars Close)
{
Close[0] = (Open[0]+High[0]+Low[0]+Close[0])/4;
Open[0] = (Open[1]+Close[1])/2;
High[0] = max(High[0],max(Open[0],Close[0]));
Low[0] = min(Low[0],min(Open[0],Close[0]));
return 8;
}
// Point-and-Figure-Balken
int bar(vars Open,vars High,vars Low,vars Close)
{
static int direction = 0;
if(direction == 1 && High[0]-Close[0] >= BarRange) {
Open[0] = round(Low[0],BarRange);
Close[0] = round(High[0],BarRange);
Low[0] = Open[0];
High[0] = Close[0];
direction = 0;
return 1;
}
if(direction == 0 && Close[0]-Low[0] >= BarRange) {
Open[0] = round(High[0],BarRange);
Close[0] = round(Low[0],BarRange);
High[0] = Open[0];
Low[0] = Close[0];
direction = 1;
return 1;
}
return 4;
}
Siehe auch:
Balken und Kerzen, Bar, BarPeriod, tick, TMF, benutzerdefinierte Funktionen
► neueste
Version online
|