multi timeframe bars

Posted By: purpledawn

multi timeframe bars - 01/17/17 20:44

Hello zorro newbye here.
I would like to model multiple price movement bar series, for eg short term, medium term, long term movement bars.
I think I understand how to adjust the primary bar series using the bar function and TimeFrame with -ve bar count, but afaik I can only use this to impact the main bar series.
How can I develop multiple custom bar series?
Can I create multiple series of TICK structs, how would I do that using series()?
Or, do I need to create an array of TICK structs for each series, if so how can I know how big the array should be? (ie, #of bar to be used in simulation, potentially realloc'd)

Or, should I use multiple series, eg a high series, low series, close series, etc for each notional bar series?

And How do I cross align my series, ie, is there a primary bar or tick index available, or do I have to use the date?

Assuming I have a series of TICKs or an array of TICKS, how can I use the various indicator functions with it?

Thank you,
Posted By: purpledawn

Re: multi timeframe bars - 01/18/17 05:27

So here is an example of mocking custom bars by managing different O/H/L/C series separately grouped by a struct. Is this the 'right' way?
can I replace customBars.Open = malloc(NumBars * sizeof(var)); memset(myBars.StartingBar, 0, NumBars * sizeof(var));
by customBars.Open = series(0) ?

typedef struct {
int* OpenBar;
vars OpenDate;
vars Open;
vars High;
vars Low;
vars Close;
vars Volume;
} CustomBars;

function initCustomBars(CustomBars* customBars){
if (is(INITRUN)) {
} else {
if (customBars->Open == NULL) { //allocate bars when NumBars is available
customBars->OpenBar = malloc(NumBars * sizeof(int)); memset(customBars->OpenBar, 0, NumBars * sizeof(int));
customBars->OpenDate = malloc(NumBars * sizeof(var)); memset(customBars->OpenDate, 0, NumBars * sizeof(var));
customBars->Open = malloc(NumBars * sizeof(var)); memset(customBars->Open, 0, NumBars * sizeof(var));
customBars->High = malloc(NumBars * sizeof(var)); memset(customBars->High, 0, NumBars * sizeof(var));
customBars->Low = malloc(NumBars * sizeof(var)); memset(customBars->Low, 0, NumBars * sizeof(var));
customBars->Close = malloc(NumBars * sizeof(var)); memset(customBars->Close, 0, NumBars * sizeof(var));
customBars->Volume = malloc(NumBars * sizeof(var)); memset(customBars->Volume, 0, NumBars * sizeof(var));
}
}

}


function run() {
static CustomBars myBars;
initCustomBars(&myBars);
}
Posted By: jcl

Re: multi timeframe bars - 01/19/17 09:40

This looks ok, but don't forget to free the memory at the end of the script. series(0) is not the same, since a series is shifted at any bar and has only the length given by LookBack.
Posted By: purpledawn

Re: multi timeframe bars - 01/20/17 06:41

Thank you. I've developped a more comprehensive script to deal with custom bars, posted here so it can help someone else. I'd be grateful if you could review the code below for inefficiencies, for eg in the way I plot an indexed series, etc.

#ifndef CUSTOMBARS
/// GENERAL CUSTOM BAR CODE - can be put in a separate include
typedef struct {
int LastBarIdx;
int LastBarNum;
int* OpenBar;
vars OpenDate;
vars Open;
vars High;
vars Low;
vars Close;
vars Price;
vars Volume;
} CustomBars;


function initCustomBars(CustomBars* customBars){
if (is(INITRUN)) {
} else {
if (customBars->Open == NULL) { //allocate bars when NumBars is available
customBars->OpenBar = malloc(NumBars * sizeof(int)); if(customBars->OpenBar == NULL)msg("Error could not allocate %i OpenBar",NumBars);memset(customBars->OpenBar, 0, NumBars * sizeof(int));
customBars->OpenDate = malloc(NumBars * sizeof(var)); if(customBars->OpenDate == NULL)msg("Error could not allocate %i OpenDate",NumBars);memset(customBars->OpenDate, 0, NumBars * sizeof(var));
customBars->Open = malloc(NumBars * sizeof(var)); if(customBars->Open == NULL)msg("Error could not allocate %i Open",NumBars);memset(customBars->Open, 0, NumBars * sizeof(var));
customBars->High = malloc(NumBars * sizeof(var)); if(customBars->High == NULL)msg("Error could not allocate %i High",NumBars);memset(customBars->High, 0, NumBars * sizeof(var));
customBars->Low = malloc(NumBars * sizeof(var)); if(customBars->Low == NULL)msg("Error could not allocate %i Low",NumBars);memset(customBars->Low, 0, NumBars * sizeof(var));
customBars->Close = malloc(NumBars * sizeof(var)); if(customBars->Close == NULL)msg("Error could not allocate %i Close",NumBars);memset(customBars->Close, 0, NumBars * sizeof(var));
customBars->Price = malloc(NumBars * sizeof(var)); if(customBars->Price == NULL)msg("Error could not allocate %i Price",NumBars);memset(customBars->Price, 0, NumBars * sizeof(var));
customBars->Volume = malloc(NumBars * sizeof(var)); if(customBars->Volume == NULL)msg("Error could not allocate %i Volume",NumBars);memset(customBars->Volume, 0, NumBars * sizeof(var));
customBars->LastBarIdx = NumBars;
customBars->LastBarNum=0;
}
}
}
function freeCustomBars(CustomBars* customBars){
//print(TO_CSV,"Bar:%i freeing OpenBar");
if (customBars->OpenBar != 0) free(customBars->OpenBar);customBars->OpenBar=0;
//print(TO_CSV,"Bar:%i freeing OpenDate");
if (customBars->OpenDate != NULL) free(customBars->OpenDate);customBars->OpenDate=0;
//print(TO_CSV,"Bar:%i freeing OpenBars");
if (customBars->Open != NULL) free(customBars->Open);customBars->Open=0;
//print(TO_CSV,"Bar:%i freeing High");
if (customBars->High != NULL) free(customBars->High);customBars->High=0;
//print(TO_CSV,"Bar:%i freeing Low");
if (customBars->Low != NULL) free(customBars->Low);customBars->Low=0;
//print(TO_CSV,"Bar:%i freeing Close");
if (customBars->Close != NULL) free(customBars->Close);customBars->Close=0;
//print(TO_CSV,"Bar:%i freeing Price");
if (customBars->Price != NULL) free(customBars->Price);customBars->Price=0;
//print(TO_CSV,"Bar:%i freeing Volume %A",customBars->Volume);
if (customBars->Volume != NULL) free(customBars->Volume);customBars->Volume=0;
//print(TO_CSV,"Bar:%i finished freeing bars n");
}
function enlarge(CustomBars* customBars){
//use if need to add more bars than originally allocated
int lastNumBars= customBars->LastBarNum;
int numCBars = ceil(lastNumBars*1.5); //expand by 50%
msg("in enlarge, lastNumBars:%i newNumBars:%i",lastNumBars,numCBars);

int* OpenBar = malloc(numCBars * sizeof(int)); if(OpenBar == NULL)msg("Error could not allocate %i OpenBar",numCBars); memset(OpenBar, 0, numCBars * sizeof(int));
vars OpenDate = malloc(numCBars * sizeof(var)); if(OpenDate == NULL)msg("Error could not allocate %i OpenDate",numCBars);memset(OpenDate, 0, numCBars * sizeof(var));
vars Open = malloc(numCBars * sizeof(var)); if(Open == NULL)msg("Error could not allocate %i Open",numCBars);memset(Open, 0, numCBars * sizeof(var));
vars High = malloc(numCBars * sizeof(var)); if(High == NULL)msg("Error could not allocate %i High",numCBars);memset(High, 0, numCBars * sizeof(var));
vars Low = malloc(numCBars * sizeof(var)); if(Low == NULL)msg("Error could not allocate %i Low",numCBars);memset(Low, 0, numCBars * sizeof(var));
vars Close = malloc(numCBars * sizeof(var)); if(Close == NULL)msg("Error could not allocate %i Close",numCBars);memset(Close, 0, numCBars * sizeof(var));
vars Price = malloc(numCBars * sizeof(var)); if(Price == NULL)msg("Error could not allocate %i Price",numCBars);memset(Price, 0, numCBars * sizeof(var));
vars Volume = malloc(numCBars * sizeof(var));if(Volume == NULL)msg("Error could not allocate %i Volume",numCBars); memset(Volume, 0, numCBars * sizeof(var));


memcpy(&OpenBar[numCBars- lastNumBars], customBars->OpenBar, lastNumBars*sizeof(int));
memcpy(&OpenDate[numCBars- lastNumBars], customBars->OpenDate, lastNumBars*sizeof(var));
memcpy(&Open[numCBars- lastNumBars], customBars->Open, lastNumBars*sizeof(var));
memcpy(&High[numCBars- lastNumBars], customBars->High, lastNumBars*sizeof(var));
memcpy(&Low[numCBars- lastNumBars], customBars->Low, lastNumBars*sizeof(var));
memcpy(&Close[numCBars- lastNumBars], customBars->Close, lastNumBars*sizeof(var));
memcpy(&Price[numCBars- lastNumBars], customBars->Price, lastNumBars*sizeof(var));
memcpy(&Volume[numCBars- lastNumBars], customBars->Volume, lastNumBars*sizeof(var));

//msg("freeing custom barS");
freeCustomBars(customBars); //for unknown reasons can get script crash freeing allocated mem
//msg("custom bars freed");


customBars->OpenBar = OpenBar;
customBars->OpenDate = OpenDate;
customBars->Open = Open;
customBars->High = High;
customBars->Low = Low;
customBars->Close = Close;
customBars->Price = Price;
customBars->Volume = Volume;

customBars->LastBarIdx = customBars->LastBarIdx + numCBars-lastNumBars;

}
function addCustomBar(CustomBars* customBars, var op, var hi, var lo, var cl, var vol){
//msg("in add custom1");
int ridx = customBars->LastBarIdx;
//print(TO_CSV,"Bar:%i closed custom bar %i op:%f hi:%f lo:%f cl:%f new bar(%f, %f, %f, %f)n",Bar,customBars->LastBarIdx,(customBars->Open)[ridx],(customBars->High)[ridx],(customBars->Low)[ridx],(customBars->Close)[ridx], op, hi, lo, cl);
ridx = customBars->LastBarIdx-1;
if (ridx < 0){
enlarge(customBars);
ridx = customBars->LastBarIdx-1;
//msg("enlarge custom bars, ridx now: %i",ridx);
}
(customBars->Open)[ridx]=op;
//msg("in add custom op: %f", op);
(customBars->High)[ridx]=hi;
(customBars->Low)[ridx]=lo;
(customBars->Close)[ridx]=cl;
(customBars->Price)[ridx]=(hi+lo+cl)/3.0;
(customBars->Volume)[ridx]=vol;

(customBars->OpenBar)[ridx]=Bar;
(customBars->OpenDate)[ridx]=wdate(0);
customBars->LastBarNum = customBars->LastBarNum+1;
customBars->LastBarIdx = ridx;
}
function updateLastCustomBar(CustomBars* customBars, var hi, var lo, var cl, var vol){
int ridx = customBars->LastBarIdx;
(customBars->High)[ridx]=max((customBars->High)[ridx],hi);
(customBars->Low)[ridx]=min((customBars->Low)[ridx],lo);
(customBars->Close)[ridx]=cl;
(customBars->Price)[ridx]=(hi+lo+cl)/3.0;
(customBars->Volume)[ridx]=(customBars->Volume)[ridx]+vol;
}

bool hasBars(CustomBars* customBars){
return (customBars->LastBarIdx) != NumBars;
}
var last(CustomBars* customBars, vars customIndexedSeries){
int idx = customBars->LastBarIdx ;
return customIndexedSeries[idx];
}
var price(CustomBars* customBars, int offset){
return last(customBars, customBars->Price);
}
vars priceSeries(CustomBars* customBars){
int idx = customBars->LastBarIdx ;
return &(customBars->Price)[idx];
}

var priceHigh(CustomBars* customBars, int offset){
return last(customBars, customBars->High);
}
vars priceHighSeries(CustomBars* customBars){
int idx = customBars->LastBarIdx ;
return &(customBars->High)[idx];
}
var priceLow(CustomBars* customBars, int offset){
return last(customBars, customBars->Low);
}
vars priceLowSeries(CustomBars* customBars){
int idx = customBars->LastBarIdx ;
return &(customBars->Low)[idx];
}

var priceOpen(CustomBars* customBars, int offset){
return last(customBars, customBars->Open);
}
vars priceOpenSeries(CustomBars* customBars){
int idx = customBars->LastBarIdx ;
return &(customBars->Open)[idx];
}

var priceClose(CustomBars* customBars, int offset){
return last(customBars, customBars->Close);
}
vars priceCloseSeries(CustomBars* customBars){
int idx = customBars->LastBarIdx ;
return &(customBars->Close)[idx];
}

var marketVol(CustomBars* customBars, int offset){
return last(customBars, customBars->Volume);
}
vars marketVolSeries(CustomBars* customBars){
int idx = customBars->LastBarIdx ;
return &(customBars->Volume)[idx];
}



function plot1(CustomBars* customBars, int barNum, string name, int colorup, int colordn){
int i = NumBars - barNum;
int startIdx = (customBars->OpenBar)[i];
int endIdx =NumBars-1; if (i > customBars->LastBarIdx) endIdx = (customBars->OpenBar)[i-1]-1;
if (startIdx == endIdx && endIdx < NumBars)
endIdx = endIdx+1;
if (PlotBars != 0){
//avoid too many bars error by not plotting outside plot zone
if(PlotBars > 0 && startIdx > PlotBars){
return;
}
if(PlotBars < 0 && endIdx < abs(PlotBars)){
return;
}
}

startIdx = NumBars - startIdx-1; endIdx = NumBars-endIdx-1;



if (colorup == 0)
colorup = BLUE;
if (colordn == 0)
colordn = RED;

int plotcolor = colorup;
bool showMsg = true;
bool isdecreasing = false;
if (i < (customBars->LastBarNum-1))
isdecreasing = (customBars->Close)[i] < (customBars->Close)[i+1]; //less than previous close
else
isdecreasing = (customBars->Close)[i] < (customBars->Open)[i];
if ( isdecreasing ){
plotcolor = colordn;
}

var lo = (customBars->Low)[i];
var hi = (customBars->High)[i];

string upName = strf("%s-Up",name);
string dnName = strf("%s-Dn",name);

if (!isdecreasing){
plotGraph(upName,startIdx,lo,LINE,plotcolor); // start point
plotGraph(upName,startIdx,hi,LINE,plotcolor); // 1st corner
plotGraph(upName,endIdx,hi,LINE,plotcolor); // 2nd corner
plotGraph(upName,endIdx,lo,LINE,plotcolor); // 3rd corner
plotGraph(upName,startIdx,lo,LINE|END,plotcolor); // 4th corner and end point
}
else {
plotGraph(dnName,startIdx,lo,LINE,plotcolor); // start point
plotGraph(dnName,startIdx,hi,LINE,plotcolor); // 1st corner
plotGraph(dnName,endIdx,hi,LINE,plotcolor); // 2nd corner
plotGraph(dnName,endIdx,lo,LINE,plotcolor); // 3rd corner
plotGraph(dnName,startIdx,lo,LINE|END,plotcolor); // 4th corner and end point
}

}
function plot(CustomBars* customBars, string name, int colorup, int colordn){
if (Bar != NumBars-1) return;

int i;
for (i = 1; i <= customBars->LastBarNum; i++){
//msg("plot bar");
plot1(customBars, i, name, colorup, colordn);
}
}


function plotLine(CustomBars* customBars, string name, vars customBarSeries, int type, int color){
int barNum; int endIdx = NumBars-1;
for (barNum = 1; barNum <= customBars->LastBarNum; barNum++){
int i = NumBars - barNum;
endIdx =NumBars-1; if (i > customBars->LastBarIdx) endIdx = (customBars->OpenBar)[i-1]-1;
endIdx = NumBars-endIdx-1;
plotGraph(name, endIdx,customBarSeries[i],LINE, color);
}
plotGraph(name, endIdx,customBarSeries[NumBars-1],LINE | END, color);
}
//plot a series indexed by customBars, ie have same number of values as customBars
function plot(CustomBars* customBars, string name, vars customBarSeries, int type, int color){
if (Bar != NumBars-1) return;
if (type == 0 or type & LINE){
//draw line graph
plotLine(customBars, name, customBarSeries, type, color);
}
else {
//...todo, handle other graph types for indexed series
}

}
/// END GENERAL CUSTOM BAR CODE - can be put in a separate include


//code to customize for each type of custom bar
function makeRandomBars(CustomBars* customBars, var probability){
if (is(INITRUN) or is(EXITRUN))
return;
initCustomBars(customBars);

static bool newBar = true;
var op = priceOpen(0);
var hi=priceHigh(0); var lo=priceLow(0); var cl=priceClose(0); var vol=marketVol(0);

if (newBar){
addCustomBar(customBars, op, hi, lo, cl, vol);
newBar = false;
}
else {
updateLastCustomBar(customBars, hi, lo, cl, vol);
}

//logic to decide when to stop bar
if (random() > (1-probability)){ //eg: close rand bar approx every probabilty base bars
newBar = true;
}
}

//renko bars
var upround(var num, var mintick){
var z = mintick*ceil(num/mintick);
return z;
}
var dnround(var num, var mintick){
var z =mintick*floor(num/mintick);
return z;
}
function addUpRenkoBoxes(CustomBars* customBars, int* rdir,var* ropen, var* rhi, var* rlo, var* rcl, var* upbox, var* dnbox, var fwdPips, var revPips, var hi, var vol, var mintick){
while (hi >= upround(*ropen + *upbox, mintick)){
*rhi = max(*rhi, upround(*ropen + *upbox,mintick));
updateLastCustomBar(customBars, *rhi, *rlo, upround(*ropen + *upbox,mintick), vol);
*ropen = *rlo = upround(*ropen + *upbox,mintick); *rdir = 1;
*upbox = fwdPips; *dnbox = revPips;
addCustomBar(customBars, *ropen, *rhi, *rlo, *ropen, 0);
}
*rhi = max(*rhi,hi);
}
function addDnRenkoBoxes(CustomBars* customBars, int* rdir,var* ropen, var* rhi, var* rlo, var* rcl, var* upbox, var* dnbox, var fwdPips, var revPips, var lo, var vol, var mintick){
while (lo <= dnround(*ropen - *dnbox, mintick)){
*rlo = min(*rlo, dnround(*ropen - *dnbox,mintick));
updateLastCustomBar(customBars, *rhi, *rlo, dnround(*ropen - *dnbox,mintick), vol);

*ropen = *rhi = dnround(*ropen - *dnbox,mintick); *rdir = -1;
*upbox = revPips; *dnbox = fwdPips;
addCustomBar(customBars, *ropen, *rhi, *rlo, *ropen, 0);
}
*rlo = min(*rlo,lo);
}
function makeRenkoBars(CustomBars* customBars, var numFwdPips, var numRevPips, var mintick, var* tmprdir, vars tmpohlcv){
static bool firstBarCreated = false;
if (is(INITRUN))
firstBarCreated = false;
if (is(INITRUN) or is(EXITRUN))
return;
initCustomBars(customBars);

static int rdir;
static var rop,rhi,rlo,rcl,rvol; //use static vars so can pass by reference
rop = tmpohlcv[0]; //initalize and store into passed in array so makeRenko can be called multiple times
rhi = tmpohlcv[1];
rlo = tmpohlcv[2];
rcl = tmpohlcv[3];
rvol = tmpohlcv[4];
rdir = *tmprdir;

if (mintick == 0)
mintick =PIP;

var op=priceOpen(0); var hi=priceHigh(0); var lo=priceLow(0); var cl=priceClose(0); var vol=marketVol(0);

var fwdPips = numFwdPips*PIP; var revPips = numRevPips*PIP;
if (rdir == 0 && rop == 0 && rcl == 0){
rop = op; rhi=rop; rlo=rop; rcl=rop;
addCustomBar(customBars, rop, rhi, rlo, rcl, 0); //open first bar
firstBarCreated = true;
}
if (rdir == 0){

if (rcl>rop && (rhi - rop) > fwdPips){
rdir = 1;
}
else if (rcl< rop && (rop - rlo) > fwdPips){
rdir = -1;
}
else if ((rhi - rop) > fwdPips){
rdir = 1;
}
else if ((rop - rlo) > fwdPips){
rdir = -1;
}
}

var upbox = fwdPips; var dnbox = revPips;
if (rdir == -1){
upbox = revPips; dnbox = fwdPips;
}
if ((rdir > 0 && cl >= op) || (rdir < 0 && cl >= op)){
//assume open lo hi cl
addDnRenkoBoxes(customBars, &rdir,&rop, &rhi, &rlo, &rcl, &upbox, &dnbox, fwdPips, revPips, lo, vol, mintick);
addUpRenkoBoxes(customBars, &rdir,&rop, &rhi, &rlo, &rcl, &upbox, &dnbox, fwdPips, revPips, hi, vol, mintick);
}
else if ((rdir < 0 && cl <= op) || (rdir > 0 && cl <= op)){
//assume open hi lo cl
addUpRenkoBoxes(customBars, &rdir,&rop, &rhi, &rlo, &rcl, &upbox, &dnbox, fwdPips, revPips, lo, vol, mintick);
addDnRenkoBoxes(customBars, &rdir,&rop, &rhi, &rlo, &rcl, &upbox, &dnbox, fwdPips, revPips, hi, vol, mintick);
}
else {
//assume open lo hi cl
addDnRenkoBoxes(customBars, &rdir,&rop, &rhi, &rlo, &rcl, &upbox, &dnbox, fwdPips, revPips, lo, vol, mintick);
addUpRenkoBoxes(customBars, &rdir,&rop, &rhi, &rlo, &rcl, &upbox, &dnbox, fwdPips, revPips, hi, vol, mintick);
}

tmpohlcv[0] = rop;
tmpohlcv[1] = rhi;
tmpohlcv[2] = rlo;
tmpohlcv[3] = rcl;
tmpohlcv[4]= rvol;
*tmprdir= rdir;

}
#define CUSTOMBARS
#endif


//testing custom bars
function run() {
//msg("create mybars");
PlotBars = 10000;
BarPeriod = 1; //if changing barperiod to higher number, depending on the boxsize, makeRenko may need to enlarge its bar array multiple times if there are many more renko bars than NumBars. This may fail

static CustomBars myBars;
//makeRandomBars(&myBars, 0.01);

static int rdir;
static var rohlcv[5] = {0,0,0,0,0};
makeRenkoBars(&myBars, 10, 3*10, PIP/10.0, &rdir, rohlcv); //10:fwdBox 3*10:reversal box PIP/10.0: mintick rounding

static CustomBars myBars2;
static int rdir2;
static var rohlcv2[5] = {0,0,0,0,0};
makeRenkoBars(&myBars2, 4*10, 4*3*10, PIP/10.0, &rdir2, rohlcv2);



plot(&myBars,"renko1",BLUE, RED);
plot(&myBars2,"renko2",0x0000AA, 0xAA0000);


if (hasBars(&myBars) && myBars.LastBarNum >= 21){
vars offsetRandClose = priceCloseSeries(&myBars);
var rsma21 = SMA(offsetRandClose, 21); //real time calculation of sma of past 21 renko bars

plot("rk1_sma21",rsma21,0,BLUE);
}
if (hasBars(&myBars2) && myBars2.LastBarNum >= 21){
vars offsetRandClose2 = priceCloseSeries(&myBars2);
var rsma212 = SMA(offsetRandClose2, 21); //real time calculation of sma of past 21 renko bars

plot("rk2_sma21",rsma212,0,0x0000CC);
}


if (is(EXITRUN)) {
msg("is Exit Run!");
freeCustomBars(&myBars);
freeCustomBars(&myBars2);
}
}
Posted By: Finstratech

Re: multi timeframe bars - 01/20/17 15:26

I assume this doesn't work for renko bars.Right?
Posted By: purpledawn

Re: multi timeframe bars - 01/21/17 06:36

Actually I built this to model renko bars. I have updated the code above with my interpretation of renko bars. enjoy.
Posted By: Finstratech

Re: multi timeframe bars - 01/23/17 15:37

Thank you. Been struggling to implement multi instrument renko application. Will try this.
Posted By: Kkaos

Re: multi timeframe bars - 02/07/17 07:08

Hi, Finstratech and purpledawn.

Finstratech I read an earlier post of yours regarding backtesting Renko bars,
which turned out v diff in live trading. Have you had any success in resolving that issue. I to have great Renko systems ( the reason I joined here today to learn how to programme them) which I want to back test.

An idea for overcoming unnecessary slippage in Renko's is creating a secondary "script" ( I have zero programming knowledge ) that can run along a running algo and future predict by at least one bar, it's 2 possible close positions (These are known values in any renko setup ). This in turn will tell you where your indicators will be at that time, and so pending orders can be placed at those levels for all and any purpose ( with OCO functions).

Ok so day one here, I need to learn how to programme in C-Lite, any recommended courses or advice ( that doesn't cost money )
I HAVE ZERO PROGRAMMING KNOWLEDGE - ABSOLUTELY ZERO.

Thanks in advance.
Posted By: pcz

Re: multi timeframe bars - 02/07/17 09:20

There's plenty of free online introductory C programming courses. For example this one is with video lectures and some kind of certificate if I'm not mistaken:

https://alison.com/courses/Diploma-in-Programming-in-C
Posted By: Kkaos

Re: multi timeframe bars - 02/07/17 11:51

Thanks, going to have a look..
Posted By: Kkaos

Re: multi timeframe bars - 02/09/17 11:53

Great link, thank you laugh
Posted By: ricky_k

Re: multi timeframe bars - 04/10/19 05:35

@purpledawn

I know this is an old thread but wondering if you've been able to update/use the code you posted for zorro custom bars. I'm interested in experimenting with portfolios using custom bars (such as tick, renko & kase bars).

Include File:
Code:
#ifndef CUSTOMBARS
/// GENERAL CUSTOM BAR CODE - can be put in a separate include
typedef struct {
int LastBarIdx;
int LastBarNum;
int* OpenBar;
vars OpenDate;
vars Open;
vars High;
vars Low;
vars Close;
vars Price;
vars Volume;
} CustomBars;


function initCustomBars(CustomBars* customBars){
if (is(INITRUN)) {
} else {
if (customBars->Open == NULL) { //allocate bars when NumBars is available
customBars->OpenBar = malloc(NumBars * sizeof(int)); if(customBars->OpenBar == NULL)msg("Error could not allocate %i OpenBar",NumBars);memset(customBars->OpenBar, 0, NumBars * sizeof(int));
customBars->OpenDate = malloc(NumBars * sizeof(var)); if(customBars->OpenDate == NULL)msg("Error could not allocate %i OpenDate",NumBars);memset(customBars->OpenDate, 0, NumBars * sizeof(var));
customBars->Open = malloc(NumBars * sizeof(var)); if(customBars->Open == NULL)msg("Error could not allocate %i Open",NumBars);memset(customBars->Open, 0, NumBars * sizeof(var));
customBars->High = malloc(NumBars * sizeof(var)); if(customBars->High == NULL)msg("Error could not allocate %i High",NumBars);memset(customBars->High, 0, NumBars * sizeof(var));
customBars->Low = malloc(NumBars * sizeof(var)); if(customBars->Low == NULL)msg("Error could not allocate %i Low",NumBars);memset(customBars->Low, 0, NumBars * sizeof(var));
customBars->Close = malloc(NumBars * sizeof(var)); if(customBars->Close == NULL)msg("Error could not allocate %i Close",NumBars);memset(customBars->Close, 0, NumBars * sizeof(var));
customBars->Price = malloc(NumBars * sizeof(var)); if(customBars->Price == NULL)msg("Error could not allocate %i Price",NumBars);memset(customBars->Price, 0, NumBars * sizeof(var));
customBars->Volume = malloc(NumBars * sizeof(var)); if(customBars->Volume == NULL)msg("Error could not allocate %i Volume",NumBars);memset(customBars->Volume, 0, NumBars * sizeof(var));
customBars->LastBarIdx = NumBars;
customBars->LastBarNum=0;
}
}
}
function freeCustomBars(CustomBars* customBars){
//print(TO_CSV,"Bar:%i freeing OpenBar");
if (customBars->OpenBar != 0) free(customBars->OpenBar);customBars->OpenBar=0;
//print(TO_CSV,"Bar:%i freeing OpenDate");
if (customBars->OpenDate != NULL) free(customBars->OpenDate);customBars->OpenDate=0;
//print(TO_CSV,"Bar:%i freeing OpenBars");
if (customBars->Open != NULL) free(customBars->Open);customBars->Open=0;
//print(TO_CSV,"Bar:%i freeing High");
if (customBars->High != NULL) free(customBars->High);customBars->High=0;
//print(TO_CSV,"Bar:%i freeing Low");
if (customBars->Low != NULL) free(customBars->Low);customBars->Low=0;
//print(TO_CSV,"Bar:%i freeing Close");
if (customBars->Close != NULL) free(customBars->Close);customBars->Close=0;
//print(TO_CSV,"Bar:%i freeing Price");
if (customBars->Price != NULL) free(customBars->Price);customBars->Price=0;
//print(TO_CSV,"Bar:%i freeing Volume %A",customBars->Volume);
if (customBars->Volume != NULL) free(customBars->Volume);customBars->Volume=0;
//print(TO_CSV,"Bar:%i finished freeing bars n");
}
function enlarge(CustomBars* customBars){
//use if need to add more bars than originally allocated
int lastNumBars= customBars->LastBarNum;
int numCBars = ceil(lastNumBars*1.5); //expand by 50%
msg("in enlarge, lastNumBars:%i newNumBars:%i",lastNumBars,numCBars);

int* OpenBar = malloc(numCBars * sizeof(int)); if(OpenBar == NULL)msg("Error could not allocate %i OpenBar",numCBars); memset(OpenBar, 0, numCBars * sizeof(int));
vars OpenDate = malloc(numCBars * sizeof(var)); if(OpenDate == NULL)msg("Error could not allocate %i OpenDate",numCBars);memset(OpenDate, 0, numCBars * sizeof(var));
vars Open = malloc(numCBars * sizeof(var)); if(Open == NULL)msg("Error could not allocate %i Open",numCBars);memset(Open, 0, numCBars * sizeof(var));
vars High = malloc(numCBars * sizeof(var)); if(High == NULL)msg("Error could not allocate %i High",numCBars);memset(High, 0, numCBars * sizeof(var));
vars Low = malloc(numCBars * sizeof(var)); if(Low == NULL)msg("Error could not allocate %i Low",numCBars);memset(Low, 0, numCBars * sizeof(var));
vars Close = malloc(numCBars * sizeof(var)); if(Close == NULL)msg("Error could not allocate %i Close",numCBars);memset(Close, 0, numCBars * sizeof(var));
vars Price = malloc(numCBars * sizeof(var)); if(Price == NULL)msg("Error could not allocate %i Price",numCBars);memset(Price, 0, numCBars * sizeof(var));
vars Volume = malloc(numCBars * sizeof(var));if(Volume == NULL)msg("Error could not allocate %i Volume",numCBars); memset(Volume, 0, numCBars * sizeof(var));


memcpy(&OpenBar[numCBars- lastNumBars], customBars->OpenBar, lastNumBars*sizeof(int));
memcpy(&OpenDate[numCBars- lastNumBars], customBars->OpenDate, lastNumBars*sizeof(var));
memcpy(&Open[numCBars- lastNumBars], customBars->Open, lastNumBars*sizeof(var));
memcpy(&High[numCBars- lastNumBars], customBars->High, lastNumBars*sizeof(var));
memcpy(&Low[numCBars- lastNumBars], customBars->Low, lastNumBars*sizeof(var));
memcpy(&Close[numCBars- lastNumBars], customBars->Close, lastNumBars*sizeof(var));
memcpy(&Price[numCBars- lastNumBars], customBars->Price, lastNumBars*sizeof(var));
memcpy(&Volume[numCBars- lastNumBars], customBars->Volume, lastNumBars*sizeof(var));

//msg("freeing custom barS");
freeCustomBars(customBars); //for unknown reasons can get script crash freeing allocated mem
//msg("custom bars freed");


customBars->OpenBar = OpenBar;
customBars->OpenDate = OpenDate;
customBars->Open = Open;
customBars->High = High;
customBars->Low = Low;
customBars->Close = Close;
customBars->Price = Price;
customBars->Volume = Volume;

customBars->LastBarIdx = customBars->LastBarIdx + numCBars-lastNumBars;

}
function addCustomBar(CustomBars* customBars, var op, var hi, var lo, var cl, var vol){
//msg("in add custom1");
int ridx = customBars->LastBarIdx;
//print(TO_CSV,"Bar:%i closed custom bar %i op:%f hi:%f lo:%f cl:%f new bar(%f, %f, %f, %f)n",Bar,customBars->LastBarIdx,(customBars->Open)[ridx],(customBars->High)[ridx],(customBars->Low)[ridx],(customBars->Close)[ridx], op, hi, lo, cl);
ridx = customBars->LastBarIdx-1;
if (ridx < 0){
enlarge(customBars);
ridx = customBars->LastBarIdx-1;
//msg("enlarge custom bars, ridx now: %i",ridx);
}
(customBars->Open)[ridx]=op;
//msg("in add custom op: %f", op);
(customBars->High)[ridx]=hi;
(customBars->Low)[ridx]=lo;
(customBars->Close)[ridx]=cl;
(customBars->Price)[ridx]=(hi+lo+cl)/3.0;
(customBars->Volume)[ridx]=vol;

(customBars->OpenBar)[ridx]=Bar;
(customBars->OpenDate)[ridx]=wdate(0);
customBars->LastBarNum = customBars->LastBarNum+1;
customBars->LastBarIdx = ridx;
}
function updateLastCustomBar(CustomBars* customBars, var hi, var lo, var cl, var vol){
int ridx = customBars->LastBarIdx;
(customBars->High)[ridx]=max((customBars->High)[ridx],hi);
(customBars->Low)[ridx]=min((customBars->Low)[ridx],lo);
(customBars->Close)[ridx]=cl;
(customBars->Price)[ridx]=(hi+lo+cl)/3.0;
(customBars->Volume)[ridx]=(customBars->Volume)[ridx]+vol;
}

bool hasBars(CustomBars* customBars){
return (customBars->LastBarIdx) != NumBars;
}
var last(CustomBars* customBars, vars customIndexedSeries){
int idx = customBars->LastBarIdx ;
return customIndexedSeries[idx];
}
var price(CustomBars* customBars, int offset){
return last(customBars, customBars->Price);
}
vars priceSeries(CustomBars* customBars){
int idx = customBars->LastBarIdx ;
return &(customBars->Price)[idx];
}

var priceHigh(CustomBars* customBars, int offset){
return last(customBars, customBars->High);
}
vars priceHighSeries(CustomBars* customBars){
int idx = customBars->LastBarIdx ;
return &(customBars->High)[idx];
}
var priceLow(CustomBars* customBars, int offset){
return last(customBars, customBars->Low);
}
vars priceLowSeries(CustomBars* customBars){
int idx = customBars->LastBarIdx ;
return &(customBars->Low)[idx];
}

var priceOpen(CustomBars* customBars, int offset){
return last(customBars, customBars->Open);
}
vars priceOpenSeries(CustomBars* customBars){
int idx = customBars->LastBarIdx ;
return &(customBars->Open)[idx];
}

var priceClose(CustomBars* customBars, int offset){
return last(customBars, customBars->Close);
}
vars priceCloseSeries(CustomBars* customBars){
int idx = customBars->LastBarIdx ;
return &(customBars->Close)[idx];
}

var marketVol(CustomBars* customBars, int offset){
return last(customBars, customBars->Volume);
}
vars marketVolSeries(CustomBars* customBars){
int idx = customBars->LastBarIdx ;
return &(customBars->Volume)[idx];
}



function plot1(CustomBars* customBars, int barNum, string name, int colorup, int colordn){
int i = NumBars - barNum;
int startIdx = (customBars->OpenBar)[i];
int endIdx =NumBars-1; if (i > customBars->LastBarIdx) endIdx = (customBars->OpenBar)[i-1]-1;
if (startIdx == endIdx && endIdx < NumBars)
endIdx = endIdx+1;
if (PlotBars != 0){
//avoid too many bars error by not plotting outside plot zone
if(PlotBars > 0 && startIdx > PlotBars){
return;
}
if(PlotBars < 0 && endIdx < abs(PlotBars)){
return;
}
}

startIdx = NumBars - startIdx-1; endIdx = NumBars-endIdx-1;



if (colorup == 0)
colorup = BLUE;
if (colordn == 0)
colordn = RED;

int plotcolor = colorup;
bool showMsg = true;
bool isdecreasing = false;
if (i < (customBars->LastBarNum-1))
isdecreasing = (customBars->Close)[i] < (customBars->Close)[i+1]; //less than previous close
else
isdecreasing = (customBars->Close)[i] < (customBars->Open)[i];
if ( isdecreasing ){
plotcolor = colordn;
}

var lo = (customBars->Low)[i];
var hi = (customBars->High)[i];

string upName = strf("%s-Up",name);
string dnName = strf("%s-Dn",name);

if (!isdecreasing){
plotGraph(upName,startIdx,lo,LINE,plotcolor); // start point
plotGraph(upName,startIdx,hi,LINE,plotcolor); // 1st corner
plotGraph(upName,endIdx,hi,LINE,plotcolor); // 2nd corner
plotGraph(upName,endIdx,lo,LINE,plotcolor); // 3rd corner
plotGraph(upName,startIdx,lo,LINE|END,plotcolor); // 4th corner and end point
}
else {
plotGraph(dnName,startIdx,lo,LINE,plotcolor); // start point
plotGraph(dnName,startIdx,hi,LINE,plotcolor); // 1st corner
plotGraph(dnName,endIdx,hi,LINE,plotcolor); // 2nd corner
plotGraph(dnName,endIdx,lo,LINE,plotcolor); // 3rd corner
plotGraph(dnName,startIdx,lo,LINE|END,plotcolor); // 4th corner and end point
}

}
function plot(CustomBars* customBars, string name, int colorup, int colordn){
if (Bar != NumBars-1) return;

int i;
for (i = 1; i <= customBars->LastBarNum; i++){
//msg("plot bar");
plot1(customBars, i, name, colorup, colordn);
}
}


function plotLine(CustomBars* customBars, string name, vars customBarSeries, int type, int color){
int barNum; int endIdx = NumBars-1;
for (barNum = 1; barNum <= customBars->LastBarNum; barNum++){
int i = NumBars - barNum;
endIdx =NumBars-1; if (i > customBars->LastBarIdx) endIdx = (customBars->OpenBar)[i-1]-1;
endIdx = NumBars-endIdx-1;
plotGraph(name, endIdx,customBarSeries[i],LINE, color);
}
plotGraph(name, endIdx,customBarSeries[NumBars-1],LINE | END, color);
}
//plot a series indexed by customBars, ie have same number of values as customBars
function plot(CustomBars* customBars, string name, vars customBarSeries, int type, int color){
if (Bar != NumBars-1) return;
if (type == 0 or type & LINE){
//draw line graph
plotLine(customBars, name, customBarSeries, type, color);
}
else {
//...todo, handle other graph types for indexed series
}

}
/// END GENERAL CUSTOM BAR CODE - can be put in a separate include


//code to customize for each type of custom bar
function makeRandomBars(CustomBars* customBars, var probability){
if (is(INITRUN) or is(EXITRUN))
return;
initCustomBars(customBars);

static bool newBar = true;
var op = priceOpen(0);
var hi=priceHigh(0); var lo=priceLow(0); var cl=priceClose(0); var vol=marketVol(0);

if (newBar){
addCustomBar(customBars, op, hi, lo, cl, vol);
newBar = false;
}
else {
updateLastCustomBar(customBars, hi, lo, cl, vol);
}

//logic to decide when to stop bar
if (random() > (1-probability)){ //eg: close rand bar approx every probabilty base bars
newBar = true;
}
}

//renko bars
var upround(var num, var mintick){
var z = mintick*ceil(num/mintick);
return z;
}
var dnround(var num, var mintick){
var z =mintick*floor(num/mintick);
return z;
}
function addUpRenkoBoxes(CustomBars* customBars, int* rdir,var* ropen, var* rhi, var* rlo, var* rcl, var* upbox, var* dnbox, var fwdPips, var revPips, var hi, var vol, var mintick){
while (hi >= upround(*ropen + *upbox, mintick)){
*rhi = max(*rhi, upround(*ropen + *upbox,mintick));
updateLastCustomBar(customBars, *rhi, *rlo, upround(*ropen + *upbox,mintick), vol);
*ropen = *rlo = upround(*ropen + *upbox,mintick); *rdir = 1;
*upbox = fwdPips; *dnbox = revPips;
addCustomBar(customBars, *ropen, *rhi, *rlo, *ropen, 0);
}
*rhi = max(*rhi,hi);
}
function addDnRenkoBoxes(CustomBars* customBars, int* rdir,var* ropen, var* rhi, var* rlo, var* rcl, var* upbox, var* dnbox, var fwdPips, var revPips, var lo, var vol, var mintick){
while (lo <= dnround(*ropen - *dnbox, mintick)){
*rlo = min(*rlo, dnround(*ropen - *dnbox,mintick));
updateLastCustomBar(customBars, *rhi, *rlo, dnround(*ropen - *dnbox,mintick), vol);

*ropen = *rhi = dnround(*ropen - *dnbox,mintick); *rdir = -1;
*upbox = revPips; *dnbox = fwdPips;
addCustomBar(customBars, *ropen, *rhi, *rlo, *ropen, 0);
}
*rlo = min(*rlo,lo);
}
function makeRenkoBars(CustomBars* customBars, var numFwdPips, var numRevPips, var mintick, var* tmprdir, vars tmpohlcv){
static bool firstBarCreated = false;
if (is(INITRUN))
firstBarCreated = false;
if (is(INITRUN) or is(EXITRUN))
return;
initCustomBars(customBars);

static int rdir;
static var rop,rhi,rlo,rcl,rvol; //use static vars so can pass by reference
rop = tmpohlcv[0]; //initalize and store into passed in array so makeRenko can be called multiple times
rhi = tmpohlcv[1];
rlo = tmpohlcv[2];
rcl = tmpohlcv[3];
rvol = tmpohlcv[4];
rdir = *tmprdir;

if (mintick == 0)
mintick =PIP;

var op=priceOpen(0); var hi=priceHigh(0); var lo=priceLow(0); var cl=priceClose(0); var vol=marketVol(0);

var fwdPips = numFwdPips*PIP; var revPips = numRevPips*PIP;
if (rdir == 0 && rop == 0 && rcl == 0){
rop = op; rhi=rop; rlo=rop; rcl=rop;
addCustomBar(customBars, rop, rhi, rlo, rcl, 0); //open first bar
firstBarCreated = true;
}
if (rdir == 0){

if (rcl>rop && (rhi - rop) > fwdPips){
rdir = 1;
}
else if (rcl< rop && (rop - rlo) > fwdPips){
rdir = -1;
}
else if ((rhi - rop) > fwdPips){
rdir = 1;
}
else if ((rop - rlo) > fwdPips){
rdir = -1;
}
}

var upbox = fwdPips; var dnbox = revPips;
if (rdir == -1){
upbox = revPips; dnbox = fwdPips;
}
if ((rdir > 0 && cl >= op) || (rdir < 0 && cl >= op)){
//assume open lo hi cl
addDnRenkoBoxes(customBars, &rdir,&rop, &rhi, &rlo, &rcl, &upbox, &dnbox, fwdPips, revPips, lo, vol, mintick);
addUpRenkoBoxes(customBars, &rdir,&rop, &rhi, &rlo, &rcl, &upbox, &dnbox, fwdPips, revPips, hi, vol, mintick);
}
else if ((rdir < 0 && cl <= op) || (rdir > 0 && cl <= op)){
//assume open hi lo cl
addUpRenkoBoxes(customBars, &rdir,&rop, &rhi, &rlo, &rcl, &upbox, &dnbox, fwdPips, revPips, lo, vol, mintick);
addDnRenkoBoxes(customBars, &rdir,&rop, &rhi, &rlo, &rcl, &upbox, &dnbox, fwdPips, revPips, hi, vol, mintick);
}
else {
//assume open lo hi cl
addDnRenkoBoxes(customBars, &rdir,&rop, &rhi, &rlo, &rcl, &upbox, &dnbox, fwdPips, revPips, lo, vol, mintick);
addUpRenkoBoxes(customBars, &rdir,&rop, &rhi, &rlo, &rcl, &upbox, &dnbox, fwdPips, revPips, hi, vol, mintick);
}

tmpohlcv[0] = rop;
tmpohlcv[1] = rhi;
tmpohlcv[2] = rlo;
tmpohlcv[3] = rcl;
tmpohlcv[4]= rvol;
*tmprdir= rdir;

}
#define CUSTOMBARS
#endif



Test code:
Code:
#include<CustomBars.c>

//testing custom bars
function run() {
//msg("create mybars");
PlotBars = 10000;
BarPeriod = 1; //if changing barperiod to higher number, depending on the boxsize, makeRenko may need to enlarge its bar array multiple times if there are many more renko bars than NumBars. This may fail

static CustomBars myBars;
//makeRandomBars(&myBars, 0.01);

static int rdir;
static var rohlcv[5] = {0,0,0,0,0};
makeRenkoBars(&myBars, 10, 3*10, PIP/10.0, &rdir, rohlcv); //10:fwdBox 3*10:reversal box PIP/10.0: mintick rounding

static CustomBars myBars2;
static int rdir2;
static var rohlcv2[5] = {0,0,0,0,0};
makeRenkoBars(&myBars2, 4*10, 4*3*10, PIP/10.0, &rdir2, rohlcv2);



plot(&myBars,"renko1",BLUE, RED);
plot(&myBars2,"renko2",0x0000AA, 0xAA0000);


if (hasBars(&myBars) && myBars.LastBarNum >= 21){
vars offsetRandClose = priceCloseSeries(&myBars);
var rsma21 = SMA(offsetRandClose, 21); //real time calculation of sma of past 21 renko bars

plot("rk1_sma21",rsma21,0,BLUE);
}
if (hasBars(&myBars2) && myBars2.LastBarNum >= 21){
vars offsetRandClose2 = priceCloseSeries(&myBars2);
var rsma212 = SMA(offsetRandClose2, 21); //real time calculation of sma of past 21 renko bars

plot("rk2_sma21",rsma212,0,0x0000CC);
}


if (is(EXITRUN)) {
msg("is Exit Run!");
freeCustomBars(&myBars);
freeCustomBars(&myBars2);
}
}




However when I test the above code (Zorro S 1.96.4) I receive this error:

Z Client S 1.96.4
(c) oP group Germany 2018
Registered to:
CustomBars_TEST -stay

CustomBars_TEST compiling..
Error in 'custombars.c' line 8:
syntax error
< vars OpenDate;
>.



I also gather from the syntax highlighting that some of the functions in the include file may clash with predefined Zorro functions.

Again just wondering if you (or anyone) has updated and/or still uses this code.
Posted By: purpledawn

Re: multi timeframe bars - 04/12/19 13:38

Hello Rick, I did develop that code further.
See the attached files -- custombars.c is an include, put in your include folder; custom_bars.c is a sample strategy using that code.
It took me a while to debug -- Enjoy!

Attached File
custombars.c  (17 downloads)
Attached File
custom_bars.c  (19 downloads)
Posted By: ricky_k

Re: multi timeframe bars - 04/13/19 16:22

purpledawn,
Thanks buddy laugh ! I'll test out the code and let you know if there's any issues that come up.

Also if I can get Kase bars (equal true range / constant volatility bars) working I'll re-post the updated code...
Cheers
ricky
Posted By: JamesHH

Re: multi timeframe bars - 02/05/20 00:36

Originally Posted by purpledawn
Hello Rick, I did develop that code further.
See the attached files -- custombars.c is an include, put in your include folder; custom_bars.c is a sample strategy using that code.
It took me a while to debug -- Enjoy!



This looks very interesting indeed.

Unfortunately, when I ran it I kept getting popup yes/no windows, and finally it crashed in the function enlarge(), where I see there are memory checks.

I will look into this further...
© 2024 lite-C Forums