Migration von algorithmischem Handelscode

Original (English)

Converting EasyLanguage, MQL4, C#, AFL, Equilla, PineScript... to C/C++

The ideal languages for algorithmic trading are C or C++, due to their speed and their access to large functions libraries and Python or R packages. But before starting serious algotrading with C/C++ and Zorro, you have probably used a traditional automated trading platform. So you want to migrate your trading strategies, "Expert Advisors", algorithms, or indicators to C or C++. Although the Zorro C/C++platform can directly run R and Python functions or Windows DLLs, it won't understand scripts from other platforms without adaption. Even when the syntax is also C or C# based, their trading functions are normally too different for an automated conversion. It's still a programmer's task. You can either hire our algo conversion service or do it yourself. Below you'll find some useful hints and examples.

Generally, Zorro can replicate any indicator and any strategy or trading algorithm from any platform. The conversion will normally result in shorter, much faster, better readable, and more robust code. Here are some examples of algorithmic trading scripts in C/C++. Many more examples for code conversion from Amibroker, TradeStation, MetaStock, or other platforms can be found in Petra Volkova's articles on Financial Hacker.

Comparing backtests and charts between different platforms

Even perfectly converted algo trading strategies can produce very different backtests and charts on different platforms. Especially MT4/MT5 backtests are often not reproducible with other platforms. When platform A produces a positve and platform B a negative backtest result of the same strategy - which one should you trust? Here's what to check for determining the reason of backtest and chart differences:

  • Compare the price data. Print out several candles with the same time stamps and check. Have they the same OHLC prices? Are they from ask, bid, or trade prices? Is the timestamp from the open, the center, or the close of the bar? UTC or a local time zone? Unadjusted or split and dividend adjusted? When using tick data, does it contain the same quotes? Forex, CFD, and cryptocurrency prices from different sources are normally very different on the minute or tick level. Candles of the same source look different dependent on price type (ask/bid/last) and time zone. Some platforms (e.g. Tradingview) do not synchronize bars to full hours or days, but to some arbitrary time. It is therefore normal and usual that even charts of the same date, asset, and source, but from two different platforms, contain different candles.
  • Compare the indicators. Are they based on the same algorithm, and return the same value? Some platforms, such as MT4, use simplified algorithms for some indicators and thus get different results. Even with an identical algorithm, cumulative indicators such as EMA or MACD can return different results especially at the begin of the simulation when the platform has a different unstable period or does not use lookback or unstable periods at all.
  • Check the script structure and bar creation. Does it run on any tick or on any bar? Are the bars aligned on the same time? Does it trade with the same market hours and weekend settings?
  • Compare the account simulation. Are lot size, leverage, margin, rollover fees, and commission considered, and are they identical? Does the platform simulate realistic order filling, or a 'naive' fill mode that enters and exits trades at the current price or at the pre-set stop or entry levels? Some platforms, even high priced options tools, do not consider spreads, transaction costs, or slippage in their results.
  • Compare optimization and backtest methods. Is the test in-sample, out-of-sample, or walk-forward? Are parameters optimized with genetic, brute force, or platform specific algorithms? In-sample backtests, as with MT4, produce normally meaningless results.
  • Compare the performance metrics. Win rate and profit factor are normally unsuspicious, but other figures such as drawdown, annual return, Sharpe ratio, or volatility are often calculated with very different methods.
     

TradeStationT, MultiChartsT, TradeSignalT

TradeStation was the first platform that supported automated trading. Its EasyLanguageT, also used by MultiCharts and in a variant named 'Equilla' by TradeSignal, has a similar design philosophy as Zorro's lite-C. Although the EasyLanguage syntax is a mix of C and Pascal, conversion to C is relatively straightforward. EasyLanguage Vars are equivalent to C data series. The first element of a series has no index, thus MyData in EasyLanguage is the same as MyData[0] in C. Keywords are case insensitive and local variables are preserved between function calls. Array indices start with 0 as in C, but in many EasyLanguage code examples you find them starting with 1. So the arrays are probably allocated with 1 extra element. Trigonometric functions (Sine, Cosine etc) expect angles in degrees (0..360), while in C and in most other languages angles are in radians (0..2*PI). Log is the logarithm base e as in C.

At the time of this writing, EasyLanguage did still not support functions, which is a strong limitation to complex projects. But separate scripts can be called like functions. The execution of an EasyLanguage script is similar to a lite-C script, with a lookback period determined by the MaxBarsBack variable. Aside from the function definitions, EasyLanguage strategies and lite-C strategies look very similar.

{ Easylanguage version }
{ Choppy Market Index Function by George Pruitt }
Inputs: periodLength(Numeric); Vars: num(0),denom(1);
if(periodLength <> 0) then
begin
denom = Highest(High,periodLength) – Lowest(Low,periodLength);
num = Close[periodLength-1] – Close;
ChoppyMarketIndex = 0.0;
if(denom <> 0) then ChoppyMarketIndex = AbsValue(num/demon)*100;
end;
// Zorro version (lite-C)
    // Choppy Market Index Function by George Pruitt
var ChoppyMarketIndex(int periodLength) { if(periodLength != 0) {
var denom = HH(periodLength) – LL(periodLength);
var num = priceClose(periodLength-1) – priceClose(0);
if(denom != 0) return abs(num/denom)*100; } return 0;
}
{ Easylanguage version }
{ enter a trade when the RSI12 crosses over 75 or under 25 }
Inputs:  
    Price(Close),LengthLE(20),LengthSE(20),
    OverSold(25),OverBought(75),StoplossPips(100),ProfitTargetPips(100);
 
variables:  
    var0(0),var1(0);
 
{ get the RSI series }
var0 = RSI( Price, LengthLE );
var1 = RSI( Price, LengthSE );
 
{ if rsi crosses over buy level, exit short and enter long }
condition1 = Currentbar > 1 and var0 crosses over OverBought ;
if condition1 then                                                                    
    Buy( "RsiLE" ) next bar at market;
 
{ if rsi crosses below sell level, exit long and enter short }
condition2 = Currentbar > 1 and var1 crosses under OverSold ;
if condition2 then                                                                    
    Sell Short( "RsiSE" ) next bar at market;
 
{ set up stop / profit levels }
SetStoploss(StoplossPips);
SetProfitTarget(ProfitTargetPips);
// Zorro version (lite-C)
// enter a trade when the RSI12 crosses over 75 or under 25
function run()
{
  BarPeriod = 60;
// get the RSI series
  vars RSIs = series(RSI(seriesC(),20));
 
// set stop / profit levels and trade duration
  Stop = 100*PIP;
  TakeProfit = 100*PIP;
  LifeTime = 24;
 
// if rsi crosses over buy level, exit short and enter long
  if(crossOver(RSIs,75))
      enterLong();
// if rsi crosses below sell level, exit long and enter short 
  if(crossUnder(RSIs,25))
      enterShort();
}

"Meta"-Trader 4 and 5

MT4T and MT5T are popular platform for retail traders and provided by many brokers. The MQL4 / MQL5 script language of their "Expert Advisors" (EAs) is based on C or C++, which would theoretically allow easy conversion to Zorro. Unfortunately, MQL4 has some issues that make "Expert Advisors" more complex and difficult to convert than scripts of other platforms. The successor MQL5 has even more issues, and consequently has never managed to replace the older MQL4.
  MQL4 and MQL5 trades require a lot of managing by script. Series are not natively supported, but must be emulated with loops and functions. Some indicators - for instance, ATR - produce different results in MQL4 than in other platforms because they are not based on the standard algorithms, but on special MQL4 variants. Candles are based on local server time, and account parameters are not normalized, so any EA must be individually adapted to the country, broker, and account. To complicate matters further, MQL4 and MQL5 do not use common trade units such as lots and pips, but calculates with "standard lots" and "points" that need to be multiplied with account-dependent conversion factors. Most code in an EA is therefore not used for the trade logic, but for patching all those issues. This results in the long and complex 'spaghetti code' that is typical for MT4 and MT4 EAs.
  For conversion, first remove the MQL4/MQL5 specific code that is not needed in lite-C, such as trade management loops, broker dependent pip and trade size calculations, and array loops that emulate series. Then the rest can be converted by replacing the MQL4 indicators and trade commands by their lite-C equivalents. Replace OnTick either with tick or run, dependent on whether the code is bar or tick based. Bar indexes are normally shifted by 1, since they refer to the new (incomplete) bar, not to the last (complete) bar. Different indicator algorithms have to be converted or replaced.

// MQL4 version of the RSI strategy (see above)
    // enter a trade when the RSI12 crosses over 75 or under 25
    int start()
    {
    // get the previous and current RSI values
       double current_rsi = iRSI(Symbol(), Period(), 12, 
         PRICE_CLOSE, 1); // mind the '1' - candle '0' is incomplete!!
       double previous_rsi = iRSI(Symbol(), Period(), 12, PRICE_CLOSE, 2);
     
    // set up stop / profit levels
       double stop = 200*Point;
       double takeprofit = 200*Point;
    
    // correction for prices with 3, 5, or 6 digits
       int digits = MarketInfo(Symbol(), MODE_DIGITS);
if (digits == 5 || digits == 3) {
stop *= 10; takeprofit *= 10; } else if (digits == 6) {
stop *= 100; takeprofit *= 100; } // find the number of trades int num_long_trades = 0; int num_short_trades = 0; int magic_number = 12345;
// exit all trades in opposite direction for(int i = 0; i < OrdersTotal(); i++) { // use OrderSelect to get the info for each trade if(!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) continue; // Trades not belonging to our EA are also found, so it's necessary to // compare the EA magic_number with the order's magic number if(magic_number != OrderMagicNumber()) continue; if(OrderType() == OP_BUY) { // if rsi crosses below sell level, exit long trades if((current_rsi < 25.0) && (previous_rsi >= 25.0)) OrderClose(OrderTicket(),OrderLots(),Bid,3,Green); else // otherwise count the trades num_long_trades++; } if(OrderType() == OP_SELL) { // if rsi crosses over buy level, exit short trades if((current_rsi > 75.0) && (previous_rsi <= 75.0)) OrderClose(OrderTicket(),OrderLots(), Ask,3,Green); else // otherwise count the trades num_short_trades++; } } // if rsi crosses over buy level, enter long if((current_rsi > 75.0) && (previous_rsi <= 75.0) && (num_long_trades == 0)) { OrderSend(Symbol(),OP_BUY,1.0,Ask,3,Ask-stop,Bid+takeprofit,"",magic_number,0,Green); } // if rsi crosses below sell level, enter short if((current_rsi < 25.0) && (previous_rsi >= 25.0) && (num_short_trades == 0)) { OrderSend(Symbol(),OP_SELL,1.0,Bid,3,Bid+stop,Ask-takeprofit,"", magic_number,0,Green); } return(0); }
Under Tips & Tricks you can find an example how to replicate MQ4-style indicator parameters with Zorro. The above mentioned issues also apply to MQL5, the "Meta"-Trader 5 script language. It has some similarities to MQL4, but offers C++ language elements and requires even more complex code for opening and managing trades.
 

NinjaTraderT

NinjaScriptT is based on C# and thus similar in syntax to Zorro's lite-C. NinjaScript also supports data series in the same way as lite-C, and its basic function list is very similar; this makes script migration rather easy. One major difference is that all NinjaTrader indicator functions return data series, while Zorro indicators return single values. Use the series function (f.i. series(indicator(..))) for making Zorro indicators also return series.

// NinjaTrader version
// Trade when a fast SMA crosses over a slow SMA
protected override void Initialize()
{ // Run OnBarUpdate on the close of each bar
CalculateOnBarClose = true; // Set stop loss and profit target at $5 and $10 SetStopLoss(CalculationMode.Ticks,5); SetProfitTarget(CalculationMode.Ticks,10); } protected override void OnBarUpdate()
{ // don't trade during the LookBack period if(CurrentBar < 20)
return; double Fast = 10; double Slow = 20; // Exit short and go long if 10 SMA crosses over 20 SMA
if(CrossAbove(SMA(Close,Fast),SMA(Close,Slow),1)) { ExitShort();
EnterLong(); } // Exit long and go short if 10 SMA crosses under 20 SMA
else if(CrossBelow(SMA(Close,Fast),SMA(Close,Slow),1)) { ExitLong();
EnterShort(); } }
// Zorro version
// Trade when a fast SMA crosses over a slow SMA
void run()
{ // Set stop loss and profit target at $5 and $10 Stop = 5; TakeProfit = 10; vars SMAFast = series(SMA(seriesC(),10)); vars SMASlow = series(SMA(seriesC(),20)); // Exit short and go long if 10 SMA crosses over 20 SMA
if(crossOver(SMAFast,SMASlow))
enterLong(); // Exit long and go short if 10 SMA crosses under 20 SMA
else if(crossUnder(SMAFast,SMASlow)) enterShort(); }
 

AmibrokerT

Amibroker's AFLT language is a C dialect, with similar syntax as lite-C. But the script structure is different. Amibroker uses "Buy" and "Sell" variables for entering trades, instead of a function call. And Amibroker calls functions for setting system parameters, instead of using variables. So it's just the opposite of what you would expect. This unusual concept has its reason in a sort of vectorized approach to a trading system, where the code mainly initializes parameters and signal conditions. Variables need not be declared, and they are usually series, as in EasyLanguage. Functions are often very similar to lite-C - for instance, Plot() or Optimize(). Others can be easily converted, f.i. Amibroker's "Explore" feature is equivalent to Zorro's print(TO_CSV).

// Amibroker version of the SMA crossing system (see above)
// Trade when a fast SMA crosses over a slow SMA
// Set stop loss and profit target at $5 and $10 ApplyStop(stopTypeLoss,stopModePoint,5,0,True,0,0,-1); ApplyStop(stopTypeProfit,stopModePoint,10,0,True,0,0,-1); SMAFast = MA(C,10); SMASlow = MA(C,20); Buy if 10 SMA crosses over 20 SMA
Buy = Cross(SMAFast,SMASlow); // Sell if 10 SMA crosses under 20 SMA
Sell = Cross(SMASlow,SMAFast);
 

TradingViewT

TradingView is a charting tool with a proprietary language named PineScriptT for defining indicators. Variables are declared by assigning a value to them, and language blocks are defined by indentation, as in Python. Functions are defined with '=>'. Data series are in reverse order compared to other platforms: the [0] element is the oldest. Aside from that, conversion to C is normally pretty straightforward. Example for a Simple Moving Average:

// PineScript version
// SMA definition
study("My sma")
my_sma(Prices, Length) =>
  Sum = Prices
  for i = 1 to Length-1
    Sum := Sum + Prices[i]
  Sum / Length
// C version
// SMA definition
var my_sma(vars Prices,int Length) { var Sum = Prices[0]; for(i = 1; i < Length; i++) Sum += Prices[i]; return Sum/Length; }
 

Neuroshell TraderT

Neuroshell Trader is a platform specialized in employing a linear neural network for automated trading. Neuroshell indicators are functions added through DLLs. They take an input array, an output array, the array size, and additional parameters. Many other trade platforms use similar DLL based indicators. Such indicators are often based on normal C, thus conversion to Zorro is very easy - especially when you don't have to convert it at all and can call the DLL function directly.
   When using an indicator made for a different platform, the array order convention must be take care of. Neuroshell stores time series in ascending order (contrary to most other platforms that store them in reverse order) and passes the end of the array, not its begin, to the indicator function. Neuroshell indicators normally return an output series instead of a single value. Below both methods of indicator conversion are shown.

// Neuroshell version - Entropy indicator
// published by ForeTrade Technologies (www.foretrade.com/entropy.htm)
#include "math.h"
#include "stdlib.h"

__declspec(dllexport) void Entropy (double *price, double *entropy, long int size, long int numbars)
{
  double *in, *out, P, G;
  long int i,j;
  double sumx = 0.0;
  double sumx2 = 0.0;
  double avgx = 0.0;
  double rmsx = 0.0;

  in=price;
  out=entropy;

  for (i=0; i<size; i++)
  {
    if (i < numbars+1) *out = 3.4e38;
    else 
    {
      sumx = sumx2 = avgx = rmsx = 0.0;
      for (j=0;j<numbars+1;j++)
      {
        sumx += log(*(in-j) / *(in-j-1)) ;
        sumx2 += log(*(in-j) / *(in-j-1)) * log(*(in-j) / *(in-j-1));
      }
      if (numbars==0) 
      {
        avgx = *in;
        rmsx = 0.0;
      }
      else 
      {
        avgx = sumx / numbars;
        rmsx = sqrt(sumx2/numbars);
      }
      P = ((avgx/rmsx)+1)/2.0;
      G = P * log(1+rmsx) + (1-P) * log(1-rmsx);
      *out=G;
    }
    in++; out++;
  }
}
// Zorro version - Entropy indicator
// Method 1 - calling the DLL function directly
// Copy the Entropy DLL into the Zorro folder
int Entropy(double *price, double *entropy, long size, long numbars); // function prototype
API(Entropy,entropy) // use the Entropy function from entropy.dll

var EntropyZ(vars Data,int Period)
{
  Period = clamp(Period,1,LookBack-1); // prevent exceeding the Data size 
  double E; // single element "array" for receiving the output value 
  Entropy(
    Data+Period+1, // end of the array (element order does not matter here)
    &E, 1,         // pointer to the output "array" with size 1
    Period); 
  return E;
}
// Zorro version - Entropy indicator
// Method 2 - converting the DLL code to lite-C
var EntropyZ(vars Data,int Period)
{
  Period = clamp(Period,1,LookBack-1); // prevent exceeding the Data size 
  var sumx = 0., sumx2 = 0.;
  int j;
  for (j=0; j<Period; j++) {
    sumx += log(Data[j]/Data[j+1]);
    sumx2 += log(Data[j]/Data[j+1]) * log(Data[j]/Data[j+1]);
  }
  var avgx = sumx/Period;
  var rmsx = sqrt(sumx2/Period);
  var P = ((avgx/rmsx)+1)/2.;
  return P * log(1+rmsx) + (1-P) * log(1-rmsx);
}

 

MatLabT

MatLab is a commercial computing environment and interactive programming language by MathWorks, Inc. It has some similarity to R, but is not specialized on data analysis and machine learning. It allows symbolic and numerical computing in all fields of mathematics. With interpreted code and accordingly slow execution, it is not suited for backtesting trading strategies (unless they are converted to a vectorized structure, which is however an awkward process). Converting MatLab code to C is also a lot of work due to the very different language syntax. Fortunately there is a better solution: MatLab has an integrated compiler that compiles a MatLab trading algorithm to a C/C++ DLL. The DLL function can then be directly called from a lite-C script.
 

See also:

Introduction to lite-C, Pointers, Structs, Functions, DLLsMT4 bridge, R bridge, Python bridge, C++ to lite-C, lite-C to C++

► latest version online

Übersetzung (Deutsch)

Konvertierung von EasyLanguage, MQL4, C#, AFL, Equilla, PineScript... zu C/C++

Die idealen Sprachen für den algorithmischen Handel sind C oder C++, aufgrund ihrer Geschwindigkeit und ihres Zugriffs auf umfangreiche Funktionsbibliotheken sowie Python- oder R-Pakete. Aber bevor Sie mit ernsthaftem Algotrading mit C/C++ und Zorro beginnen, haben Sie wahrscheinlich eine traditionelle automatisierte Handelsplattform verwendet. Also möchten Sie Ihre Handelsstrategien, "Expert Advisors", Algorithmen oder Indikatoren zu C oder C++ migrieren. Obwohl die Zorro C/C++-Plattform direkt R und Python-Funktionen oder Windows-DLLs ausführen kann, versteht sie Skripte von anderen Plattformen ohne Anpassung nicht. Selbst wenn die Syntax ebenfalls auf C oder C# basiert, sind ihre Handelsfunktionen normalerweise zu unterschiedlich für eine automatisierte Konvertierung. Es bleibt also eine Aufgabe für Programmierer. Sie können entweder unseren Algo-Konvertierungsservice beauftragen oder es selbst tun. Unten finden Sie einige nützliche Hinweise und Beispiele.

Im Allgemeinen kann Zorro jeden Indikator und jede Strategie oder jeden Handels Algorithmus von jeder Plattform replizieren. Die Konvertierung führt normalerweise zu kürzerem, deutlich schnellerem, besser lesbarem und robusterem Code. Hier sind einige Beispiele von algorithmischen Handels-Skripten in C/C++. Viele weitere Beispiele für die Code-Konvertierung von Amibroker, TradeStation, MetaStock oder anderen Plattformen finden Sie in Petra Volkovas Artikeln auf Financial Hacker.

Vergleich von Backtests und Charts zwischen verschiedenen Plattformen

Sogar perfekt konvertierte Algo-Trading-Strategien können sehr unterschiedliche Backtests und Charts auf verschiedenen Plattformen erzeugen. Besonders MT4/MT5-Backtests sind oft nicht mit anderen Plattformen reproduzierbar. Wenn Plattform A ein positives und Plattform B ein negatives Backtestergebnis derselben Strategie erzeugt - welcher sollte Ihnen vertrauen? Hier ist, was Sie überprüfen sollten, um den Grund für Unterschiede in Backtests und Charts zu bestimmen:

  • Vergleichen Sie die Preisdaten. Drucken Sie mehrere Kerzen mit denselben Zeitstempeln aus und überprüfen Sie. Haben sie dieselben OHLC Preise? Sind sie von Ask-, Bid- oder Trade-Preisen? Ist der Zeitstempel vom Open, Center oder Close der Kerze? UTC oder eine lokale Zeitzone? Unangepasst oder gesplittet und dividenden angepasst? Beim Verwenden von Tick-Daten, enthalten sie dieselben Quotes? Forex-, CFD- und Kryptowährungspreise von verschiedenen Quellen sind normalerweise sehr unterschiedlich auf der Minuten- oder Tick-Ebene. Kerzen derselben Quelle sehen je nach Preistyp (Ask/Bid/Last) und Zeitzone unterschiedlich aus. Einige Plattformen (z.B. Tradingview) synchronisieren Kerzen nicht auf volle Stunden oder Tage, sondern auf eine willkürliche Zeit. Daher ist es normal und üblich, dass sogar Charts desselben Datums, Assets und Quelle, aber von zwei verschiedenen Plattformen, unterschiedliche Kerzen enthalten.
  • Vergleichen Sie die Indikatoren. Basieren sie auf demselben Algorithmus, und liefern denselben Wert? Einige Plattformen, wie MT4, verwenden vereinfachte Algorithmen für einige Indikatoren und erhalten dadurch unterschiedliche Ergebnisse. Selbst mit einem identischen Algorithmus können kumulative Indikatoren wie EMA oder MACD unterschiedliche Ergebnisse liefern, besonders zu Beginn der Simulation, wenn die Plattform eine andere instabile Periode hat oder gar keine Lookback- oder instabilen Perioden verwendet.
  • Überprüfen Sie die Skriptstruktur und die Kerzenbildung. Läuft es auf jedem Tick oder auf jeder Kerze? Sind die Kerzen zur gleichen Zeit ausgerichtet? Handelt es mit denselben Marktzeiten und Wochenend Einstellungen?
  • Vergleichen Sie die Kontosimulation. Sind Lotgröße, Hebel, Margin, Rollover-Gebühren und Kommission berücksichtigt und identisch? Simuliert die Plattform realistisches Order-Filling oder einen 'naiven' Fill-Modus, der Trades zum aktuellen Preis oder zu voreingestellten Stop- oder Entry-Leveln ein- und aussteigt? Einige Plattformen, sogar hochpreisige Optionswerkzeuge, berücksichtigen Spreads, Transaktionskosten oder Slippage in ihren Ergebnissen nicht.
  • Vergleichen Sie Optimierungs und Backtest Methoden. Ist der Test in-sample, out-of-sample oder walk-forward? Werden Parameter mit genetischen, brute-force oder plattformspezifischen Algorithmen optimiert? In-sample Backtests, wie bei MT4, liefern normalerweise bedeutungslose Ergebnisse.
  • Vergleichen Sie die Performance-Metriken. Gewinnrate und Profitfaktor sind normalerweise unbedenklich, aber andere Kennzahlen wie Drawdown, Jahresrendite, Sharpe-Ratio oder Volatilität werden oft mit sehr unterschiedlichen Methoden berechnet.
     

TradeStationT, MultiChartsT, TradeSignalT

TradeStation war die erste Plattform, die automatisierten Handel unterstützte. Ihre EasyLanguageT, ebenfalls verwendet von MultiCharts und in einer Variante namens 'Equilla' von TradeSignal, hat eine ähnliche Designphilosophie wie Zorros lite-C. Obwohl die EasyLanguage-Syntax eine Mischung aus C und Pascal ist, ist die Konvertierung zu C relativ unkompliziert. EasyLanguage Vars sind äquivalent zu C Datenreihen. Das erste Element einer Reihe hat keinen Index, daher ist MyData in EasyLanguage dasselbe wie MyData[0] in C. Schlüsselwörter sind nicht groß-/kleinschreibungssensitiv und lokale Variablen werden zwischen Funktionsaufrufen beibehalten. Array-Indizes beginnen mit 0 wie in C, aber in vielen EasyLanguage-Codebeispielen beginnen sie mit 1. Daher sind die Arrays wahrscheinlich mit einem zusätzlichen Element reserviert. Trigonometrische Funktionen (Sine, Cosine usw.) erwarten Winkel in Grad (0..360), während in C und in den meisten anderen Sprachen Winkel in Radiant (0..2*PI) sind. Log ist der Logarithmus zur Basis e wie in C.

Zum Zeitpunkt dieses Schreibens unterstützte EasyLanguage noch keine Funktionen, was eine starke Einschränkung für komplexe Projekte darstellt. Aber separate Skripte können wie Funktionen aufgerufen werden. Die Ausführung eines EasyLanguage-Skripts ist ähnlich wie ein lite-C-Skript, mit einem Lookback-Zeitraum, der durch die MaxBarsBack Variable bestimmt wird. Abgesehen von den Funktionsdefinitionen sehen EasyLanguage-Strategien und lite-C-Strategien sehr ähnlich aus.

{ Easylanguage version }
{ Choppy Market Index Function by George Pruitt }
Inputs: periodLength(Numeric); Vars: num(0),denom(1);
if(periodLength <> 0) then
begin
denom = Highest(High,periodLength) – Lowest(Low,periodLength);
num = Close[periodLength-1] – Close;
ChoppyMarketIndex = 0.0;
if(denom <> 0) then ChoppyMarketIndex = AbsValue(num/demon)*100;
end;
// Zorro version (lite-C)
    // Choppy Market Index Function by George Pruitt
var ChoppyMarketIndex(int periodLength) { if(periodLength != 0) {
var denom = HH(periodLength) – LL(periodLength);
var num = priceClose(periodLength-1) – priceClose(0);
if(denom != 0) return abs(num/denom)*100; } return 0;
}
{ Easylanguage version }
{ enter a trade when the RSI12 crosses over 75 or under 25 }
Inputs:  
    Price(Close),LengthLE(20),LengthSE(20),
    OverSold(25),OverBought(75),StoplossPips(100),ProfitTargetPips(100);
 
variables:  
    var0(0),var1(0);
 
{ get the RSI series }
var0 = RSI( Price, LengthLE );
var1 = RSI( Price, LengthSE );
 
{ if rsi crosses over buy level, exit short and enter long }
condition1 = Currentbar > 1 and var0 crosses over OverBought ;
if condition1 then                                                                    
    Buy( "RsiLE" ) next bar at market;
 
{ if rsi crosses below sell level, exit long and enter short }
condition2 = Currentbar > 1 and var1 crosses under OverSold ;
if condition2 then                                                                    
    Sell Short( "RsiSE" ) next bar at market;
 
{ set up stop / profit levels }
SetStoploss(StoplossPips);
SetProfitTarget(ProfitTargetPips);
// Zorro version (lite-C)
// enter a trade when the RSI12 crosses over 75 or under 25
function run()
{
  BarPeriod = 60;
// get the RSI series
  vars RSIs = series(RSI(seriesC(),20));
 
// set stop / profit levels and trade duration
  Stop = 100*PIP;
  TakeProfit = 100*PIP;
  LifeTime = 24;
 
// if rsi crosses over buy level, exit short and enter long
  if(crossOver(RSIs,75))
      enterLong();
// if rsi crosses below sell level, exit long and enter short 
  if(crossUnder(RSIs,25))
      enterShort();
}

"Meta"-Trader 4 und 5

MT4T und MT5T sind beliebte Plattformen für Retail-Trader und werden von vielen Brokern angeboten. Die MQL4 / MQL5 Skriptsprache ihrer "Expert Advisors" (EAs) basiert auf C oder C++, was theoretisch eine einfache Konvertierung zu Zorro ermöglichen würde. Leider hat MQL4 einige Probleme, die "Expert Advisors" komplexer und schwieriger zu konvertieren machen als Skripte anderer Plattformen. Der Nachfolger MQL5 hat noch mehr Probleme und hat es daher nie geschafft, das ältere MQL4 zu ersetzen.
  MQL4 und MQL5-Trades erfordern viel Verwaltung durch Skripte. Serien werden nicht nativ unterstützt, sondern müssen mit Schleifen und Funktionen emuliert werden. Einige Indikatoren - zum Beispiel ATR - liefern in MQL4 andere Ergebnisse als in anderen Plattformen, weil sie nicht auf den Standardalgorithmen basieren, sondern auf speziellen MQL4-Varianten. Kerzen basieren auf der lokalen Serverzeit, und Kontoparameter sind nicht normalisiert, sodass jedes EA individuell an das Land, den Broker und das Konto angepasst werden muss. Um die Dinge weiter zu verkomplizieren, verwenden MQL4 und MQL5 keine gängigen Handelsgrößen wie Lots und Pips, sondern berechnen mit "Standard Lots" und "Points", die mit kontobezogenen Umrechnungsfaktoren multipliziert werden müssen. Der meiste Code in einem EA wird daher nicht für die Handelslogik verwendet, sondern um all diese Probleme zu beheben. Dies führt zu dem langen und komplexen 'Spaghetti-Code', der typisch für MT4 und MT4-EAs ist.
  Für die Konvertierung entfernen Sie zunächst den spezifischen MQL4/MQL5-Code, der in lite-C nicht benötigt wird, wie Handelsverwaltungs-Schleifen, brokerabhängige Pip- und Handelsgrößenberechnungen sowie Array-Schleifen, die Serien emulieren. Dann kann der Rest durch Ersetzen der MQL4-Indikatoren und Handelsbefehle durch ihre lite-C-Äquivalente konvertiert werden. Ersetzen Sie OnTick entweder durch tick oder run, abhängig davon, ob der Code bar- oder tickbasiert ist. Bar-Indizes werden normalerweise um 1 verschoben, da sie sich auf die neue (unvollständige) Bar und nicht auf die letzte (vollständige) Bar beziehen. Unterschiedliche Indikatoralgorithmen müssen konvertiert oder ersetzt werden.

// MQL4-Version der RSI-Strategie (siehe oben)
    // Einen Trade eingehen, wenn der RSI12 über 75 oder unter 25 kreuzt
    int start()
    {
    // Holen Sie sich die vorherigen und aktuellen RSI-Werte
       double current_rsi = iRSI(Symbol(), Period(), 12, 
         PRICE_CLOSE, 1); // beachten Sie die '1' - Kerze '0' ist unvollständig!!
       double previous_rsi = iRSI(Symbol(), Period(), 12, PRICE_CLOSE, 2);
     
    // Stop-/Profit-Level festlegen
       double stop = 200*Point;
       double takeprofit = 200*Point;
    
    // Korrektur für Preise mit 3, 5 oder 6 Dezimalstellen
       int digits = MarketInfo(Symbol(), MODE_DIGITS);
if (digits == 5 || digits == 3) {
stop *= 10; takeprofit *= 10; } else if (digits == 6) {
stop *= 100; takeprofit *= 100; } // Anzahl der Trades ermitteln int num_long_trades = 0; int num_short_trades = 0; int magic_number = 12345;
// Alle Trades in die entgegengesetzte Richtung schließen for(int i = 0; i < OrdersTotal(); i++) { // Verwenden Sie OrderSelect, um die Informationen für jeden Trade zu erhalten if(!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) continue; // Trades, die nicht zu unserem EA gehören, werden ebenfalls gefunden, daher ist es notwendig, // die EA-Magic-Number mit der Magic-Number der Order zu vergleichen if(magic_number != OrderMagicNumber()) continue; if(OrderType() == OP_BUY) { // wenn der RSI unter das Verkaufsniveau kreuzt, Long-Trades schließen if((current_rsi < 25.0) && (previous_rsi >= 25.0)) OrderClose(OrderTicket(),OrderLots(),Bid,3,Green); else // andernfalls die Trades zählen num_long_trades++; } if(OrderType() == OP_SELL) { // wenn der RSI über das Kaufniveau kreuzt, Short-Trades schließen if((current_rsi > 75.0) && (previous_rsi <= 75.0)) OrderClose(OrderTicket(),OrderLots(), Ask,3,Green); else // andernfalls die Trades zählen num_short_trades++; } } // wenn der RSI über das Kaufniveau kreuzt, Long eingehen if((current_rsi > 75.0) && (previous_rsi <= 75.0) && (num_long_trades == 0)) { OrderSend(Symbol(),OP_BUY,1.0,Ask,3,Ask-stop,Bid+takeprofit,"",magic_number,0,Green); } // wenn der RSI unter das Verkaufsniveau kreuzt, Short eingehen if((current_rsi < 25.0) && (previous_rsi >= 25.0) && (num_short_trades == 0)) { OrderSend(Symbol(),OP_SELL,1.0,Bid,3,Bid+stop,Ask-takeprofit,"", magic_number,0,Green); } return(0); }
Unter Tipps & Tricks finden Sie ein Beispiel, wie Sie MQ4-ähnliche Indikatorparameter mit Zorro replizieren können. Die oben genannten Probleme gelten auch für MQL5, die "Meta"-Trader 5 Skriptsprache. Sie hat einige Ähnlichkeiten zu MQL4, bietet jedoch C++ Sprachelemente und erfordert noch komplexeren Code zum Öffnen und Verwalten von Trades.
 

NinjaTraderT

NinjaScriptT basiert auf C# und ist daher in der Syntax ähnlich wie Zorros lite-C. NinjaScript unterstützt auch Datenreihen auf die gleiche Weise wie lite-C, und seine grundlegende Funktionsliste ist sehr ähnlich; dies erleichtert die Skriptmigration erheblich. Ein wesentlicher Unterschied besteht darin, dass alle NinjaTrader-Indikatorfunktionen Datenreihen zurückgeben, während Zorro-Indikatoren einzelne Werte zurückgeben. Verwenden Sie die series-Funktion (z.B. series(indicator(..))), um Zorro-Indikatoren ebenfalls Datenreihen zurückgeben zu lassen.

// NinjaTrader version
// Trade when a fast SMA crosses over a slow SMA
protected override void Initialize()
{ // Run OnBarUpdate on the close of each bar
CalculateOnBarClose = true; // Set stop loss and profit target at $5 and $10 SetStopLoss(CalculationMode.Ticks,5); SetProfitTarget(CalculationMode.Ticks,10); } protected override void OnBarUpdate()
{ // don't trade during the LookBack period if(CurrentBar < 20)
return; double Fast = 10; double Slow = 20; // Exit short and go long if 10 SMA crosses over 20 SMA
if(CrossAbove(SMA(Close,Fast),SMA(Close,Slow),1)) { ExitShort();
EnterLong(); } // Exit long and go short if 10 SMA crosses under 20 SMA
else if(CrossBelow(SMA(Close,Fast),SMA(Close,Slow),1)) { ExitLong();
EnterShort(); } }
// Zorro version
// Trade when a fast SMA crosses over a slow SMA
void run()
{ // Set stop loss and profit target at $5 and $10 Stop = 5; TakeProfit = 10; vars SMAFast = series(SMA(seriesC(),10)); vars SMASlow = series(SMA(seriesC(),20)); // Exit short and go long if 10 SMA crosses over 20 SMA
if(crossOver(SMAFast,SMASlow))
enterLong(); // Exit long and go short if 10 SMA crosses under 20 SMA
else if(crossUnder(SMAFast,SMASlow)) enterShort(); }
 

AmibrokerT

Amibrokers AFLT-Sprache ist ein C-Dialekt mit ähnlicher Syntax wie lite-C. Aber die Skriptstruktur ist anders. Amibroker verwendet "Buy" und "Sell" Variablen zum Eingeben von Trades, anstatt eines Funktionsaufrufs. Und Amibroker ruft Funktionen zum Festlegen von Systemparametern auf, anstatt Variablen zu verwenden. Es ist also genau das Gegenteil dessen, was man erwarten würde. Dieses ungewöhnliche Konzept hat seinen Grund in einem sortierten, vektorbasierten Ansatz für ein Handelssystem, bei dem der Code hauptsächlich Parameter und Signalbedingungen initialisiert. Variablen müssen nicht deklariert werden und sind normalerweise Serien, wie in EasyLanguage. Funktionen sind oft sehr ähnlich wie lite-C - zum Beispiel Plot() oder Optimize(). Andere können leicht konvertiert werden, z.B. ist Amibrokers "Explore"-Funktion gleichbedeutend mit Zorros print(TO_CSV).

// Amibroker version of the SMA crossing system (see above)
// Trade when a fast SMA crosses over a slow SMA
// Set stop loss and profit target at $5 and $10 ApplyStop(stopTypeLoss,stopModePoint,5,0,True,0,0,-1); ApplyStop(stopTypeProfit,stopModePoint,10,0,True,0,0,-1); SMAFast = MA(C,10); SMASlow = MA(C,20); Buy if 10 SMA crosses over 20 SMA
Buy = Cross(SMAFast,SMASlow); // Sell if 10 SMA crosses under 20 SMA
Sell = Cross(SMASlow,SMAFast);
 

TradingViewT

TradingView ist ein Charting-Tool mit einer proprietären Sprache namens PineScriptT zur Definition von Indikatoren. Variablen werden durch Zuweisen eines Wertes deklariert, und Sprachblöcke werden durch Einrückung definiert, wie in Python. Funktionen werden mit '=>' definiert. Datenreihen sind im Vergleich zu anderen Plattformen in umgekehrter Reihenfolge: das [0] Element ist das älteste. Abgesehen davon ist die Konvertierung zu C normalerweise ziemlich unkompliziert. Beispiel für einen einfachen gleitenden Durchschnitt:

// PineScript version
// SMA definition
study("My sma")
my_sma(Prices, Length) =>
  Sum = Prices
  for i = 1 to Length-1
    Sum := Sum + Prices[i]
  Sum / Length
// C version
// SMA definition
var my_sma(vars Prices,int Length) { var Sum = Prices[0]; for(i = 1; i < Length; i++) Sum += Prices[i]; return Sum/Length; }
 

Neuroshell TraderT

Neuroshell Trader ist eine Plattform, die sich auf den Einsatz eines linearen neuronalen Netzwerks für automatisierten Handel spezialisiert hat. Neuroshell-Indikatoren sind Funktionen, die über DLLs hinzugefügt werden. Sie nehmen ein Eingabearray, ein Ausgabearray, die Array-Größe und zusätzliche Parameter. Viele andere Handelsplattformen verwenden ähnliche DLL-basierte Indikatoren. Solche Indikatoren basieren oft auf normalem C, daher ist die Konvertierung zu Zorro sehr einfach - besonders, wenn Sie es überhaupt nicht konvertieren müssen und die DLL-Funktion direkt aufrufen können.
   Beim Verwenden eines für eine andere Plattform erstellten Indikators muss die Array-Reihenfolgen-Konvention beachtet werden. Neuroshell speichert Zeitreihen in aufsteigender Reihenfolge (im Gegensatz zu den meisten anderen Plattformen, die sie in umgekehrter Reihenfolge speichern) und übergibt das Ende des Arrays, nicht den Anfang, an die Indikatorfunktion. Neuroshell-Indikatoren geben normalerweise eine Ausgabereihe statt eines einzelnen Wertes zurück. Unten werden beide Methoden der Indikator-Konvertierung gezeigt.

// Neuroshell version - Entropy indicator
// veröffentlicht von ForeTrade Technologies (www.foretrade.com/entropy.htm)
#include "math.h"
#include "stdlib.h"

__declspec(dllexport) void Entropy (double *price, double *entropy, long int size, long int numbars)
{
  double *in, *out, P, G;
  long int i,j;
  double sumx = 0.0;
  double sumx2 = 0.0;
  double avgx = 0.0;
  double rmsx = 0.0;

  in=price;
  out=entropy;

  for (i=0; i<size; i++)
  {
    if (i < numbars+1) *out = 3.4e38;
    else 
    {
      sumx = sumx2 = avgx = rmsx = 0.0;
      for (j=0;j<numbars+1;j++)
      {
        sumx += log(*(in-j) / *(in-j-1)) ;
        sumx2 += log(*(in-j) / *(in-j-1)) * log(*(in-j) / *(in-j-1));
      }
      if (numbars==0) 
      {
        avgx = *in;
        rmsx = 0.0;
      }
      else 
      {
        avgx = sumx / numbars;
        rmsx = sqrt(sumx2/numbars);
      }
      P = ((avgx/rmsx)+1)/2.0;
      G = P * log(1+rmsx) + (1-P) * log(1-rmsx);
      *out=G;
    }
    in++; out++;
  }
}
// Zorro version - Entropy indicator
// Methode 1 - direkt die DLL-Funktion aufrufen
// Kopieren Sie die Entropy DLL in den Zorro-Ordner
int Entropy(double *price, double *entropy, long size, long numbars); // Funktionsprototyp
API(Entropy,entropy) // Verwenden Sie die Entropy-Funktion aus entropy.dll
    
var EntropyZ(vars Data,int Period)
{
  Period = clamp(Period,1,LookBack-1); // verhindern, dass die Datenmenge überschritten wird 
  double E; // einzelnes Element "Array" zum Empfangen des Ausgabe-Wertes 
  Entropy(
    Data+Period+1, // Ende des Arrays (Elementreihenfolge spielt hier keine Rolle)
    &E, 1,         // Zeiger auf das Ausgabe-"Array" mit Größe 1
    Period); 
  return E;
}
// Zorro version - Entropy indicator
// Methode 2 - Konvertierung des DLL-Codes zu lite-C
var EntropyZ(vars Data,int Period)
{
  Period = clamp(Period,1,LookBack-1); // verhindern, dass die Datenmenge überschritten wird 
  var sumx = 0., sumx2 = 0.;
  int j;
  for (j=0; j<Period; j++) {
    sumx += log(Data[j]/Data[j+1]);
    sumx2 += log(Data[j]/Data[j+1]) * log(Data[j]/Data[j+1]);
  }
  var avgx = sumx/Period;
  var rmsx = sqrt(sumx2/Period);
  var P = ((avgx/rmsx)+1)/2.;
  return P * log(1+rmsx) + (1-P) * log(1-rmsx);
}

 

MatLabT

MatLab ist eine kommerzielle Rechenumgebung und eine interaktive Programmiersprache von MathWorks, Inc. Sie weist einige Ähnlichkeiten zu R auf, ist aber nicht auf Datenanalyse und maschinelles Lernen spezialisiert. Sie ermöglicht symbolisches und numerisches Rechnen in allen Bereichen der Mathematik. Mit interpretiertem Code und entsprechend langsamer Ausführung ist sie nicht geeignet für Backtesting von Handelsstrategien (es sei denn, sie werden in eine vektorisierte Struktur konvertiert, was jedoch ein umständlicher Prozess ist). Die Konvertierung von MatLab-Code zu C ist ebenfalls viel Arbeit aufgrund der sehr unterschiedlichen Sprachsyntax. Glücklicherweise gibt es eine bessere Lösung: MatLab verfügt über einen integrierten Compiler, der einen MatLab-Handelsalgorithmus zu einer C/C++ DLL kompiliert. Die DLL-Funktion kann dann direkt aus einem lite-C-Skript aufgerufen werden.
 

Siehe auch:

Einführung in lite-C, Zeiger, Strukturen, Funktionen, DLLsMT4-Bridge, R-Bridge, Python-Bridge, C++ zu lite-C, lite-C zu C++

► neueste Version online