~~~ Zorro Script Examples ~~~
Zorro runs scripts in C++ or
plain C, with some added objects and keywords ('function', 'var', 'string', 'series', etc.) for
shorter, easier-to-read code. Due to its very effective
compiler, C is the fastest high-level language (see
computer languages comparison) and thus ideally suited for
trading strategy backtests. Find below some typical scripts for algorithmic trading, financial market
analysis, or other purposes. To learn how to write algo trading
strategies in C, begin with a
tutorial. To convert code
from other platforms - in Easylanguage, Pinescript, AFL, MQL4
etc - to C, 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 12 years 1-minute price history from the broker's server.
function main()
{
StartDate = 20100101 // YYYYMMDD format
EndDate = NOW; // up to today
assetAdd("AAPL"); // Ticker to download
int Mode = 1; // 1 for M1 data, 0 for tick data
int Source = 0; // 0 = from connected broker
assetHistory(0,Mode|Source); // download data
}
Trivial Trading System
~~~~~~~~~~~~~~
Basic trend following strategy 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 reversal.
function run() // at any bar
{
vars MovingAverages = series(SMA(seriesC(),300));
Stop = ATR(100); // set stoploss distance
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.
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!
 #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;
}
|