~~~ Algo Trading with C/C++ - Code Examples ~~~


Zorro runs algorithmic trading scripts in C++ or plain C, with some added objects and types ('function', 'var', 'string', 'series') for shorter, easier-to-read code. Due to the very effective compiler, C and C++ are the fastest high-level languages (see computer languages comparison) and thus ideally suited for high resolution algo trading backtests. Find below some typical scripts for automated trading, financial data analysis, or general purposes. To learn how to write algo trading strategies in C or C++, begin with a tutorial. To convert code from other platforms - in Easylanguage, Pinescript, AFL, MQL4 etc - read about code migration. To check out a specific trading function, follow its link in the function list. And if you don't want to code yourself, hire our algo trading development service.


Download Price History ~~~~~~~~~~~~~

Download daily price history from an online source.
function main()
{
  StartDate = 20100101; // YYYYMMDD format
  EndDate = NOW;  // up to today
  assetHistory("AAPL",FROM_YAHOO); // download AAPL data
}


Trivial Trading System ~~~~~~~~~~~~~~

Basic trend following system that enters a long position when the close price crosses the moving average from below, and a short position when it crosses from above. Exit by adaptive stop and reversal.
function run() // at any bar
{
  vars MovingAverages = series(SMA(seriesC(),300));
  Stop = ATR(100); // set stoploss distance dependent on volatility
  if(crossOver(seriesC(),MovingAverages))
    enterLong(); // exit short, enter long on Price/MA cross
  else if(crossUnder(seriesC(),MovingAverages))
    enterShort(); // and vice versa
}  


Broker Arbitrage HFT System ~~~~~~~~~~~~~

Detect and exploit tiny EUR/USD price differences of two different forex brokers with a HFT trading script. Backtest with historical data from both brokers in tick resolution.
function main() // run at start
{
  LookBack = 0; // no lookback period
  set(TICKS); // tick-based backtest
  History = "*.t1";  // tick-based historical data file
  assetList("AssetsArb.csv"); // asset list with symbols
}

function tick()  // the HFT part; runs at any incoming tick
{
  asset("EURUSD_A"); // EUR/USD from broker A
  var SpreadA = marketVal(), PriceA = priceC(); 
  asset("EURUSD_B"); // EUR/USD from broker B
  var SpreadB = marketVal(), PriceB = priceC()

  var Threshold = 1.5*(SpreadA + SpreadB); 
  var Difference = PriceA - PriceB; 

  asset("EURUSD_A");
  if(NumOpenShort and Difference < 0) 
    exitShort(); // take profit
  else if(NumOpenLong and Difference > 0) 
    exitLong(); // take profit
  else if(!NumOpenShort and Difference > Threshold) 
    enterShort(); // go short with the expensive asset
  else if(!NumOpenLong and Difference < -Threshold) 
    enterLong(); // go long with the cheap asset
  
  asset("EURUSD_B");
  if(NumOpenShort and Difference > 0) 
   exitShort();
  else if(NumOpenLong and Difference < 0) 
    exitLong();
  else if(!NumOpenShort and Difference < -Threshold) 
    enterShort();
  else if(!NumOpenLong and Difference > Threshold) 
    enterLong();
}


Machine Learning System ~~~~~~~~~~~~~~

Feed several price curve characteristics, such as the recent high/low ranges and momentums, to a decision tree trading algorithm. Use the prediction from the decision treee for entering long or short positions. This system uses walk-forward analysis, which is mandatory for optimized strategies or machine learning algorithms.
function run()
{
  set(RULES); // generate trading rules
  StartDate = 2012;
  EndDate = 2022; // backtest / training period
  BarPeriod = 240; // 4 hours
  LookBack = 200;
  NumWFOCycles = 10; // activate walk-forward analysis
  ReTrainDays = 60; // re-train live system every 2 months
	
  while(asset(loop("EUR/USD","AUD/USD","GBP/USD")))
  {
// generate signals for a decision tree
    var Range1 = priceH(0)-priceL(0);
    var Range2 = priceH(1)-priceL(1));
    var Trend = priceC(0)-SMA(seriesC(),LookBack);
    var Momentum1 = priceC(0) - priceC(1);
    var Momentum2 = priceC(1) - priceC(2);
		
    if(Train) Hedge = 2; // allow long+short in training
    LifeTime = 1440/BarPeriod; 	// 1 day prediction horizon
    
// generate decision tree, train on trade returns, 
// predict next trade in test/live mode
    var LongPrediction = adviseLong(DTREE+RETURNS,0,
      Range1,Range2,Momentum1,Momentum2,Trend);
    var ShortPrediction = adviseShort(DTREE+RETURNS,0,
      Range1,Range2,Momentum1,Momentum2,Trend);
    if(Train or (LongPrediction > 0 and ShortPrediction < 0))
      enterLong(); // in training or at favorable prediction 
    if(Train or (ShortPrediction > 0 and LongPrediction < 0))
      enterShort();
  }
}


Options Selling System ~~~~~~~~~

This algo trading strategy exploits the option sellers advantage. It finds call and put options of the same premium and enters 6-week strangle combos. If an option expires in the money and is exercised, the underlying is immediately sold.
void run() 
{
  BarPeriod = 1440; // 1 day
  BarZone = EST;
  BarOffset = 9*60+30; // market open time
  asset("SPY");

// load today's contract chain
  if(!contractUpdate(Asset,0,CALL|PUT)) return;
// wait until previous combo was expired or exercised
  if(NumOpenShort) return;
// if excercised, sell remaining underlying at market 
  contractSellUnderlying();

// open a new put/call strangle
  int Days = 45; // minimum days to expiration
  var Premium = 3; // get 600 dollars per combo
  Multiplier = 100;
  if(combo( // find matching options
    contractFind(CALL,Days,Premium,2),1, 
    contractFind(PUT,Days,Premium,2),1,
    0,0,0,0)) 
  {
    MarginCost = comboMargin(-1,3);
    enterShort(comboLeg(1)); // sell combo
    enterShort(comboLeg(2));
  }
}


Indicator (Laguerre Filter) ~~~~~~~~~~~~~~~

The Laguerre filter is a low-lag lowpass filter, excellent for trend following systems and superior to traditional SMA or EMA indicators.
var Laguerre(vars Data, var alpha)
{
  var alpha1 = 1.-alpha;
  vars L = series(Data[0],8);
  L[0] = alpha*Data[0] + alpha1*L[1];
  L[2] = -alpha1*L[0] + L[1] + alpha1*L[3];
  L[4] = -alpha1*L[2] + L[3] + alpha1*L[5];
  L[6] = -alpha1*L[4] + L[5] + alpha1*L[7];
  return (L[0]+2.*L[2]+2.*L[4]+L[6])/6.;
} 


Plot Average Spread by Hour ~~~~~~~~~~~~~

This script visualizes the average ask-bid spread of the selected asset on any hour of the day in a histogram chart. Forex pairs often have spread jumps between the US and pacific session. Do not trade during that time.
function run()
{
  BarPeriod = 15;  // 15 minutes per histogram bar
  StartDate = 2019;
  EndDate = 2022;
  plotBar("Spread",(60*hour(0)+minute(0))/BarPeriod,tod(0),
    marketVal(0),AVG|BARS,RED);
}


Plot Price Distribution Histogram ~~~~~~~~~~~~

Compares the price distributions - the frequencies of prices - of two assets. Assets with an unusually small price distribution - smaller than the classical bell curve - can be used for channel trading, for instance with a grid trading system.
function run()
{
  BarPeriod = 60;
  StartDate = 2019;
  EndDate = 2022;
  asset("EUR/CHF");
  var PriceCHF = price(0);
  asset("EUR/USD");
  var PriceUSD = price(0);
  plotBar("EUR/CHF",1000*PriceCHF,PriceCHF,1,SUM|BARS,RED); 
  plotBar("EUR/USD",1000*PriceUSD,PriceUSD,1,SUM|BARS,GREEN);
}


Plot Price Cycles Spectrum ~~~~~~~~~~~~~~~~

Displays a frequency spectrum, i.e. the strength of any cycle of the price curve, over the last month.
function run()
{
  BarPeriod = 60;
  StartDate = ymd(wdate(NOW)-30); // last 30 days
  EndDate = ymd(wdate(NOW)); 
  LookBack = 2000;
  int Cycle;
  for(Cycle = 10; Cycle < 200; Cycle++)
    plotBar("Spectrum",Cycle,Cycle,
      Spectrum(Price,Cycle,4*Cycle),BARS|AVG,BLUE);
}


Plot Current Order Flow Profile ~~~~~~~~~~~~~~

Reads the order book from the connected broker and plots an ask/bid profile that makes imbalances in the order flow immediately visible.
function main() 
{
  StartDate = NOW;
  asset("BTC/USD");
// load current order book
  int N = orderUpdate("BTCUSD",1);
  T2* Quotes = dataStr(1,OrderRow,0);
  printf("\nOrderbook: %i quotes",N);
// evaluate order book +/- 5% range
  var Distance = 0.05*priceC(0); 
  int N2 = orderCVD(Quotes,N,Distance);
  printf(", %i in 5% range",N2);
  var Level = priceC(0) - Distance; // start level
  int i;
  for(i=0; i<100; i++) {
    Level += Distance/50;
    plotBar("Ask",i,Level,cpd(Level),BARS|LBL2,RED);
  }
  Level = priceClose() - Distance;
  for(i=0; i<100; i++) {
    Level += Distance/50;
    plotBar("Bid",i,Level,cpd(-Level),BARS|LBL2,BLUE);
  }
} 


Non-Linear Reinvestment Calculator ~~~~~~~~

Systems with high leverage require non-linear reinvestment of profits for limiting drawdown depths. Set up initial capital, accumulated profit, and linearity with the 3 Zorro sliders and get the suggested reinvestment amount. The rest of the profit should remain on the account for buffering drawdowns.
function main()
{
  slider(1,10000,1,20000,"Capital","Initial capital");
  slider(2,10000,0,20000,"Profit","Collected profit");
  slider(3,2000,1000,2000,".Root","Nth root"); 
// N = 1.000 for linear reinvesting, 
// N = 2.000 for square root reinvesting
  while(wait(100)) // update info while moving sliders
    print(TO_INFO,"Investment: $%.0f",
      slider(1)*pow(1+slider(2)/slider(1),
      1./(0.001*slider(3))));
} 

 
Mass text replacing ~~~~~~~~~~~~~~~~~~~

Example for working with files and text strings. Insert a "viewport" statement in the headers of all HTML files in a folder, then upload the changed files via FTP to a web server.
void main()
{
  string Folder = "c:\\project\\zorro\\manual\\", 
  URL = "ftp://zorro-project.com/manual/en", // web server
  Old = "</head>", // where to insert
  New = 
   "<meta name=\"viewport\" content=\"width=device-width\">\n</head>";
  string Buffer = zalloc(1000000); // just a large buffer
  string FileName = file_next(strf("%s*.htm",Folder)); // first file
  while(FileName) {
    string FilePath = strf("%s%s",Folder,FileName); // generate path
    string Content = file_content(FilePath); // read file into string
    if(Content && !strstr(Content,"viewport")) { // no viewport yet?
      strx(Buffer,1000000,Content,Old,New); // replace text
      file_write(FilePath,Buffer,0); // save modified file
      ftp_upload(URL,FilePath,"User","Password"); // upload to server
      printf("\n%s updated",FileName);
    }
    FileName = file_next(0); // get next file
  }
}

 
Print 2000 digits of Pi ~~~~~~~~~~~~~~~~~~~

With an algorithm from a math book.
void main()
{
  int num=0,a=10000,b,c,d,e=0,gg;
  int f[14000];
  for(b=14000; b>0; b--) f[b] = 2000; 
  for(c=14000; c>0; c-=14) {
    d = 0;
    gg = c*2;
    for(b=c; b>0; b--)  {
       d += f[b]*a;
       gg--;
       f[b] = d%gg;
       d /= gg;
       gg--;
       d *= b;
    }
    printf("%.4d",e+d/a);
    e = d%a;
    num += 4;
  }
  printf("\n%d digits of pi calculated!",num);
}


Display a Mandelbrot Fractal ~~~~~~~~~~~~~~~~~~~

Zorro script of a standard Windows app with window class, menu, message loop, and interactive graphics. For hardcore programmers only!
 
Zorro Script for Mandelbrot Fractals
#include <windows.h>

LRESULT CALLBACK WndProc(HWND hWnd, 
  UINT message, WPARAM wParam, LPARAM lParam);

int WINAPI main(WINARGS)
{
//Create and register a window - the basic stuff
  char *szClass = "ZorroWindowClass";
  HINSTANCE hi = GetModuleHandle(NULL);
  UnregisterClass(szClass,hi);

  WNDCLASSEX wcex;
  wcex.cbSize = sizeof(WNDCLASSEX);
  wcex.style = CS_HREDRAW|CS_VREDRAW;
  wcex.lpfnWndProc = WndProc;
  wcex.cbClsExtra = 0;
  wcex.cbWndExtra = 0;
  wcex.hInstance = hi;
  wcex.hIcon = LoadIcon(hi,(LPCSTR)128);
  wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
  wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
  wcex.lpszMenuName = NULL;
  wcex.lpszClassName = szClass;
  wcex.hIconSm = LoadIcon(hi,(LPCSTR)128);
  RegisterClassEx(&wcex);
  HWND hwnd=CreateWindowEx(0,szClass,
    "Zorro Mandelbrot Test",0x96cf0000,0,0,640,480,NULL,0,NULL,NULL);

// now create a "Reset" and "Quit" menu 
  HMENU menu = CreateMenu();
  HMENU hSubMenu = CreateMenu();
  InsertMenu(hSubMenu,0,MF_BYPOSITION|MF_STRING,1,"Reset");
  InsertMenu(hSubMenu,2,MF_BYPOSITION|MF_STRING,3,"Quit");
  InsertMenu(menu,0,
    MF_BYPOSITION|MF_STRING|MF_POPUP,(UINT_PTR)hSubMenu,"File");

// activate window, menu, and message loop
  if(hwnd) {
    SetMenu(hwnd,menu);
    ShowWindow(hwnd,SW_SHOW);
    MSG msg;
    while(GetMessage(&msg, NULL, 0, 0)) {
      TranslateMessage(&msg);
      DispatchMessage(&msg);
    }
  }
  return 0;
}

// convert value to color
long JetColor(double v)
{
  double d = 25.0;
  v = v/d + 0.5;
  int f = (int)(255*(v-i));
  int r=0, g=0, b=0;

  switch((int)v) {
    case 0: r=0; g=0; b=f; break;
    case 1: r=0; g=f; b=255; break;
    case 2: r=f; g=255; b=255-f;break;
    case 3: r=255; g=255-f;b=0; break;
    case 4: r=255-f;g=0; b=0; break;
  }
  return r|(g<<8)|(b<<16);
}

// Draw the Mandelbrot fractal.
  double m_x = 0.344142, 
    m_y = 0.075094, 
    m_width = 0.017813;

  void Draw(HDC hdc,long vw,long vh)
  {
    long w = (long)vw, h = (long)vh, i,j;
    long detail=100;

    if(w>0) {
      for(i=0; i<w; i++)
      for(j=0; j<h; j++) {
        double x = m_x+((double)i)*m_width/w;
        double y = m_y+((double)(h-j))*m_width/w;
        double zx = 0,zy = 0;
        int inset = 1, times = 0;
        while(inset && times<detail) {
          times++;
          double zxs = zx*zx;
          double zys = zy*zy;
          zy = 2*zx*zy+y;
          zx = zxs-zys+x;
          if (zxs+zys >= 4.0) inset=0;
        }
        if(inset) SetPixel(hdc,i,j,0);
        else SetPixel(hdc,i,j,JetColor(times));
      }
    }
  }
}

// Windows message loop
LRESULT CALLBACK WndProc(HWND hWnd, 
  UINT message, WPARAM wParam, LPARAM lParam)
{
  PAINTSTRUCT ps;
  HDC hdc;
  switch(message) {
    case WM_RBUTTONDOWN: // reset to full fractal
      m_x = -2.5;
      m_y = -2;
      m_width = 4.0;
      InvalidateRect(hWnd,0,0);
      break;
    case WM_LBUTTONDOWN: { // zoom in at cursor position
      RECT rect;
      GetClientRect(hWnd,&rect);
      long x = ((long)lParam)&0xffff;
      long y = (((long)lParam)&0xffff0000)>>16;
      double zoom = 0.5;
      double a = x; a /= rect.right; m_x += m_width*(a-0.5);
      a = y; a /= rect.bottom; m_y += m_width*(0.5-a);
      m_width *= zoom;
      InvalidateRect(hWnd,0,0);
      break;
    }
    case WM_DESTROY:
      PostQuitMessage(0);
      break;
    case WM_COMMAND:
      switch(wParam) {
        case 1:
          m_x=-2.5; m_y=-2; m_width=4.0;
          InvalidateRect(hWnd,0,0);
          break;
        case 2: break;
        case 3:
          PostMessage(hWnd, WM_CLOSE,0,0);
          break;
       }
       break;
    case WM_PAINT:
      hdc = BeginPaint(hWnd, &ps);
      RECT rect;
      GetClientRect(hWnd,&rect);
      Draw(hdc,rect.right,rect.bottom);
      EndPaint(hWnd, &ps);
      break;
    case WM_KEYDOWN:
      switch( wParam ) {
        case VK_ESCAPE:
        case VK_F12:
          PostMessage(hWnd, WM_CLOSE,0,0);
          break;
       }
       break;
    default:
     return DefWindowProc(hWnd, message, wParam, lParam);
  }
  return 0;
}

 
 
"Take Money From The Rich And Give It To The Poor"