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.
- 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.
- 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