How to Change the Time Axis to Strike Price in Amibroker?

I wish to plot open interest (on Y axis) and strike price (on X axis). How can it be done on amibroker? It is intended to generate an option pain chart

Thanks
Shrimohan

Yes, it can be done. But you can not use plot since it uses DateTime array for x-axis.

Either use Gfx functionality or XY chart feature of explorer (scroll to bottom here as well as go to links here and here).


Since you seem to be Indian below are Gfx examples I posted to some other Indian few years ago on Indian forum (as proof that is is very well possible).
CFf3NGv IC4qRlx

5 Likes

@shrimohan, this past thread provide some guidance (no code) to create a custom X-axis (using Gfx functions).
Similar logic will apply to the Y-axis.

1 Like

FWIW, as I said in previous thread simplest quickest way is using XYchart* via Explorer (Gfx* is too advanced for beginner. It is not required to get basic plotting done.)

There is not much to do other than setting XYChartSetAxis and iterating XYChartAddPoint. You just have to worry about where you get the data from. Since it is non time based data you may store to multi-dim array (-> Matrix functions).

Once it is stored...

matexplore = /*Your matrix here having Strike & OI data columns*/; // matrix storing Strikes, OI

rownum = MxGetSize( matexplore, 0 );|
colnum = MxGetSize( matexplore, 1 );|

Filter = 0;	

chartname = "OI_Optionchain Calls";
XYChartSetAxis( chartname, "[Strikes]", "[OI Calls]", chartStyle = styleHistogram );

// OI calls
for( i = 0; i < rownum; i++ ) {		
	x = matexplore[i][0]; // strikes
	y = matexplore[i][1]; // OI
	XYChartAddPoint( chartname, "", x, y, colorBlueGrey );	
}

// similar for OI puts below...
chartname = "OI_Optionchain Puts";
XYChartSetAxis( chartname, "[Strikes]", "[OI Puts]", chartStyle );
// ....etc.

And That's it. No Gfx hassle at all!

Resulting in
43 58 14

OI data of upper pics being directly called from this sample website

4 Likes

hey thanks buddy... i tried using XYChart and this seems to work fine. Stage 1 cleared. About data, I am scrapping from my trading terminal so i have real time data with me. Stage 2 is making the code run automatically so i can get option pain analysis in real time. Although the analysis can run in 1s mode but it changes the window again to Result List

I tried the XYChart axis method and it worked great. Although will also explore the GFX as many suggested it to be the best!

@shrimohan Could you please share working code , if you don't mind . Would like to test in similar lines

surely i will... just working on it for some bug removal and once the code gets completed i will post it surely as Live OI Analysis for Option Pain

For Live Open Interest Analysis

Here is the working code with example. I did not make the graph as of now as i only needed the level of expiry as per Max Pain Theory

Modifications welcome!

_SECTION_BEGIN("Formula 3");

CellHeight = 20;
CellWidth = 90;

function PrintInCell(string, row, col)
{
GfxDrawText(string, colCellWidth, rowCellHeight, (col+1)*CellWidth, (row+1)*CellHeight, 0);
}

//Formatting Data
GfxSetOverlayMode(2);
GfxSelectFont("Tahoma", 8);

start = 11300;

call_pain_sum = 0;
put_pain_sum = 0;

//Table Headers
PrintInCell("Strike",0,0);
PrintInCell("Calls",0,1);
PrintInCell("Puts",0,2);
PrintInCell("Call Pain",0,3);
PrintInCell("Puts Pain",0,4);
PrintInCell("Option Pain",0,5);
PrintInCell("PCR",0,6);

for(i=0;i<31;i++)
{
strike[i] = (start - 700) + 50*i;
PrintInCell(NumToStr(strike[i]),i+1,0);
call_oi[i] = LastValue(Foreign("NIFTYWK" + strike[i] + "CE", "I"));
put_oi[i] = LastValue(Foreign("NIFTYWK" + strike[i] + "PE", "I"));
PrintinCell(NumToStr(call_oi[i]),i+1,1);
PrintinCell(NumToStr(put_oi[i]),i+1,2);
PrintinCell(NumToStr(put_oi[i]/call_oi[i]),i+1,6);
}

for(i=0;i<31;i++)
{
call_pain_sum = 0;
put_pain_sum = 0;
//Call Pain
for(j=i;j>0;j--)
{
call_pain_sum = call_pain_sum + (strike[j]-strike[j-1])*call_oi[j-1];
}
call_pain[i] = call_pain_sum;
PrintinCell(NumToStr(call_pain[i]),i+1,3);
//Put Pain
for(j=i+1;j<31;j++)
{
put_pain_sum = put_pain_sum + (strike[j]-strike[j-1])*put_oi[j];
}
put_pain[i] = put_pain_sum;
PrintinCell(NumToStr(put_pain[i]),i+1,4);
option_pain[i] = call_pain[i] + put_pain[i];
PrintinCell(NumToStr(option_pain[i]),i+1,5);
}

//Finding the Minimum Pain
temp = option_pain[0];
for(i=0;i<31;i++)
{
if(temp>option_pain[i])
{
temp = option_pain[i];
expiry = strike[i];
}
}
GfxSelectFont("Tohma", 12);
GfxSetTextColor(colorBlue);
GfxTextOut("Expiry likely to be at " + NumToStr(expiry), 220, 658);

_SECTION_END();

image

1 Like

@shrimohan, when you post some code, you should use the REQUIRED code tags.

immagine

Anyway, here is a little improved formula to achieve a more visually pleasant layout.
I only reviewed some Gfx related code (did not change any calculations logic).
Please, note that to test it, I had to "fake" some values (lines marked with "// TO_REMOVE).

_SECTION_BEGIN( "Options Pain Table" );

lm = 8; // table left margin
tm = 4; // table top margin
cellHeight = 20;
cellWidth  = 70;
rowColor = colorDefault; // will be reassigned to alternate row colors in "table"
colorBlueAlt = ColorRGB( 72, 73, 200 ); // alternative hue of blue

// Text centered in a cell
function PrintInCellC( string, row, col )
{
	local x1, y1, x2, y2;
	
    x1 = lm + ( col * cellWidth );
    x2 = x1 + cellWidth;
    y1 = tm + ( row * cellHeight );
    y2 = y1 + cellHeight;
    GfxFillSolidRect( x1 + 1, y1 + 1, x2 - 1, y2 - 1, colorBlue );
    GfxDrawText( string, x1 + 3, y1 + 3, x2 - 3, y2 - 3, 1 + 4 + 32 ); // text centered
}

// Text centered in "merged" cell
function PrintSummaryCellC( string, row, cols )
{
	local x1, y1, x2, y2;
    x1 = lm; 
    x2 = x1 + (cols +1) * cellWidth;
    y1 = tm + ( row * cellHeight );
    y2 = y1 + cellHeight;
    GfxFillSolidRect( x1 + 1, y1 + 1, x2 - 1, y2 - 1, colorDarkRed );
    GfxDrawText( string, x1 + 3, y1 + 3, x2 - 3, y2 - 3, 1 + 4 + 32 ); // text centered
}

// Text right aligned 
function PrintInCell( string, row, col )
{
	local x1, y1, x2, y2;
    x1 = lm + ( col * cellWidth );
    x2 = x1 + cellWidth;
    y1 = tm + ( row * cellHeight );
    y2 = y1 + cellHeight;
    GfxFillSolidRect( x1 + 1, y1 + 1, x2 - 1, y2 - 1, rowColor ); // uses a color defined elsewhere in the code
    GfxDrawText( string, x1 + 3, y1 + 3, x2 - 3, y2 - 3, 2 + 4 + 32 ); // text right aligned
}

// General GFx settings
GfxSetOverlayMode( 2 ); // display only low-level graphics
GfxSelectFont( "Tahoma", 8, 600 );
GfxSetBkMode( 1 ); // transparent

start = 11300;

call_pain_sum = 0;
put_pain_sum = 0;

// Columns Headers
GfxSetTextColor( colorYellow );
//Table Headers
PrintInCellC( "Strike", 0, 0 );
PrintInCellC( "Calls", 0, 1 );
PrintInCellC( "Puts", 0, 2 );
PrintInCellC( "Call Pain", 0, 3 );
PrintInCellC( "Puts Pain", 0, 4 );
PrintInCellC( "Option Pain", 0, 5 );
PrintInCellC( "PCR", 0, 6 );

// Table rows
GfxSetTextColor( ColorRGB( 223, 223, 255 ) );
GfxSelectFont( "Tahoma", 8, 400 );

for( i = 0; i < 31; i++ )
{
    rowColor = IIf( i % 2, colorDarkBlue, colorBlueAlt );

    strike[i] = ( start - 700 ) + 50 * i;
    PrintInCell( NumToStr( strike[i], 1 ), i + 1, 0 );
    // call_oi[i] = i * 10; // LastValue( Foreign( "NIFTYWK" + strike[i] + "CE", "I" ) ); // To uncomment
    // put_oi[i] = i * 3; // LastValue( Foreign( "NIFTYWK" + strike[i] + "PE", "I" ) );   // To uncomment  
    call_oi[i] = Max(3, i * 5 + floor(mtRandom() * 25));   // TO_REMOVE - Used only to test the formula
    put_oi[i]  = Max(2, i * 5 + floor(mtRandom() * 25));   // TO_REMOVE - Used only to test the formula
    PrintinCell( NumToStr( call_oi[i], 1 ), i + 1, 1 );
    PrintinCell( NumToStr( put_oi[i], 1 ), i + 1, 2 );
    PrintinCell( NumToStr( put_oi[i] / call_oi[i] ), i + 1, 6 );
}

for( i = 0; i < 31; i++ )
{
    rowColor = IIf( i % 2, colorDarkBlue, colorBlueAlt );
    call_pain_sum = 0;
    put_pain_sum = 0;

    // Call Pain
    for( j = i; j > 0; j-- )
    {
        call_pain_sum = call_pain_sum + ( strike[j] - strike[j - 1] ) * call_oi[j - 1];
    }

    call_pain[i] = call_pain_sum;
    PrintinCell( NumToStr( call_pain[i], 1 ), i + 1, 3 );

    // Put Pain
    for( j = i + 1; j < 31; j++ )
    {
        put_pain_sum = put_pain_sum + ( strike[j] - strike[j - 1] ) * put_oi[j];
    }

    put_pain[i] = put_pain_sum;
    PrintinCell( NumToStr( put_pain[i], 1), i + 1, 4 );
    option_pain[i] = call_pain[i] + put_pain[i];
    PrintinCell( NumToStr( option_pain[i], 1 ), i + 1, 5 );
}

// Finding the Minimum Pain
expire = 0;
temp = option_pain[0];

for( i = 0; i < 31; i++ )
{
    if( temp > option_pain[i] )
    {
        temp = option_pain[i];
        expiry = strike[i];
    }
}

// Draw summary/message row
GfxSelectFont( "Tahoma", 9, 800 ); // Make it bolder
GfxSetTextColor( colorYellow );
PrintSummaryCellC( "Expiry likely to be at " + NumToStr( expiry , 1), 32, 6 ); // pass the row and the toal of cols used

_SECTION_END();

Result:
immagine

I also used the NumToStr() second parameter (format) to remove some unneeded decimals.

The above is a simple example, that can be further improved (for instance consolidating the "PrintInCell..." functions using some extra parameters like colors to use, text alignment, etc.).

Search the forum and the Amibroker KB to learn more about the many functionalities offered by the low-level graphics functions.

6 Likes

Thanks for the Update @beppe. The new GFX is very attractive

@shrimohan and all,

first of all if you copy code then you should add reference to where it comes from originally
https://www.amibroker.com/guide/h_lowlevelgfx.html
https://www.amibroker.com/guide/afl/gfxdrawtext.html

Next you should read about Understanding how AFL works.
You should prefer array processing in first place.
And you definitely do not need nested loop in your case at all.

So instead of this

for( i = 0; i < 31; i++ )
{
    rowColor = IIf( i % 2, colorDarkBlue, colorBlueAlt );
    call_pain_sum = 0;
    put_pain_sum = 0;
    
    // Call Pain
    for( j = i; j > 0; j-- )
    {
        call_pain_sum = call_pain_sum + ( strike[j] - strike[j - 1] ) * call_oi[j - 1];
    }

    call_pain[i] = call_pain_sum;
    PrintinCell( NumToStr( call_pain[i], 1 ), i + 1, 3 );

    // Put Pain
    for( j = i + 1; j < 31; j++ )
    {
        put_pain_sum = put_pain_sum + ( strike[j] - strike[j - 1] ) * put_oi[j];
    }
    put_pain[i] = put_pain_sum;
    PrintinCell( NumToStr( put_pain[i], 1), i + 1, 4 );
    option_pain[i] = call_pain[i] + put_pain[i];
    PrintinCell( NumToStr( option_pain[i], 1 ), i + 1, 5 );
}

You can just write more crispy code via arrays. Mostly you need loop for PrintInCell only.

// Call Pain
rev_strike = (strike-Nz(Ref(strike, -1))) * Nz(Ref(call_oi, -1));
call_pain = SumSince(bi == 0, rev_strike);

// Put Pain
rev_strike = (Ref(strike,1)-strike) * Ref(put_oi,1);
put_pain = Reverse(SumSince(bi==BarCount-endval, Reverse(rev_strike)));
//
option_pain = call_pain + put_pain;

rowColor = IIf( BarIndex() % 2, colorDarkBlue, colorBlueAlt );
for ( i = 0; i < Min(31, BarCount); i++ ) 
{
    PrintinCell( NumToStr( call_pain[i], 1 ), i + 1, 3, rowcolor[i], right );
    PrintinCell( NumToStr( put_pain[i], 1), i + 1, 4, rowcolor[i], right );   
    PrintinCell( NumToStr( option_pain[i], 1 ), i + 1, 5, rowcolor[i], right ); 
}

Instead of this

// Finding the Minimum Pain
expire = 0;
temp = option_pain[0];
for( i = 0; i < 31; i++ )
{
    if( temp > option_pain[i] )
    {
        temp = option_pain[i];
        expiry = strike[i];
    }
}

you can just write this

// Finding the Minimum Pain
bi = BarIndex();
temp = SparseCompress(bi<31, option_pain);
temp = Lowest(temp);
expiry = Ref( SparseCompress(bi<31,strike), -LowestBars(temp));

etc.

So here is entire improvement (and using just two custom functions):

_SECTION_BEGIN( "Options Pain Table" );
/// @link http://www.amibroker.com/guide/h_lowlevelgfx.html
/// @link https://www.amibroker.com/guide/afl/gfxdrawtext.html
/// @link https://forum.amibroker.com/t/how-to-change-the-time-axis-to-strike-price-in-amibroker/11708/10
/// improved array version without nested loop etc.
/// @link https://forum.amibroker.com/t/how-to-change-the-time-axis-to-strike-price-in-amibroker/11708/12
lm = 8; // table left margin
tm = 4; // table top margin
cellHeight = 20;
cellWidth  = 70;
start = 10600;

bi = BarIndex();
strike = start + 50 * bi;
endval = Min(31, BarCount);
colorBlueAlt = ColorRGB( 72, 73, 200 ); // alternative hue of blue
rowColor = IIf( bi % 2, colorDarkBlue, colorBlueAlt );

// Text centered in "merged" cell
function PrintSummaryCellC( string, row, col )
{
	local x1, y1, x2, y2;
    x1 = lm; 
    x2 = x1 + col * cellWidth;
    y1 = tm + row * cellHeight;
    y2 = y1 + cellHeight;
    GfxFillSolidRect( x1 + 1, y1 + 1, x2 - 1, y2 - 1, colorDarkRed );
    GfxDrawText( string, x1 + 3, y1 + 3, x2 - 3, y2 - 3, 1 + 4 + 32 ); // text centered
}

function PrintInCell( string, row, col, color, align )
{
	local x1, y1, x2, y2;
    x1 = lm + col * cellWidth;
    x2 = x1 + cellWidth;
    y1 = tm + row * cellHeight;
    y2 = y1 + cellHeight;
    GfxFillSolidRect( x1 + 1, y1 + 1, x2 - 1, y2 - 1, color );
    GfxDrawText( string, x1 + 3, y1 + 3, x2 - 3, y2 - 3, align );
}

// Text right aligned 
right = 2 + 4 + 32;
// Text centered in a cell
centered = 1 + 4 + 32;

// General GFx settings
GfxSetOverlayMode( 2 ); // display only low-level graphics
GfxSelectFont( "Tahoma", 8, 600 );
GfxSetBkMode( 1 ); // transparent

// Columns Headers
GfxSetTextColor( colorYellow );

//Table Headers
header = "Strike,Calls,Puts,Call Pain,Puts Pain,OptionPain,PCR";
for ( i = 0; i <= 6; i++ ) 
	PrintInCell( StrExtract(header, i), 0, i, colorBlue, align = centered );

// Table rows
GfxSetTextColor( ColorRGB( 223, 223, 255 ) );
GfxSelectFont( "Tahoma", 8, 400 );

call_oi = Max(3, bi * 5 + floor(mtRandomA() * 25));   // TO_REMOVE - Used only to test the formula
put_oi = Max(2, bi * 5 + floor(mtRandomA() * 25));   // TO_REMOVE - Used only to test the formula

// To uncomment
//for ( i = 0; i < endval; i++ ) {
    // call_oi[i] = LastValue( Foreign( "NIFTYWK" + strike[i] + "CE", "I" ) );  // To uncomment
    // put_oi[i] = LastValue( Foreign( "NIFTYWK" + strike[i] + "PE", "I" ) );  // To uncomment 
//}

// Call Pain
rev_strike = (strike - Nz(Ref(strike, -1))) * Nz(Ref(call_oi, -1));
call_pain = SumSince(bi == 0, rev_strike);

// Put Pain
rev_strike = (Ref(strike,1)-strike) * Ref(put_oi,1);
put_pain = Reverse(SumSince(bi==BarCount-endval, Reverse(rev_strike)));

option_pain = call_pain + put_pain;
pcr = put_oi / (call_oi+1e-9);

for ( i = 0; i < endval; i++ ) {    
	row = i+1;
	PrintInCell( NumToStr( strike[i], 1 ), row, 0, rowcolor[i], right );
	PrintinCell( NumToStr( call_oi[i], 1 ), row, 1, rowcolor[i], right );
	PrintinCell( NumToStr( put_oi[i], 1 ), row, 2, rowcolor[i], right );
	PrintinCell( NumToStr( pcr[i] ), row, 6, rowcolor[i], right );
	PrintinCell( NumToStr( call_pain[i], 1 ), row, 3, rowcolor[i], right );
	PrintinCell( NumToStr( put_pain[i], 1), row, 4, rowcolor[i], right ); 
	PrintinCell( NumToStr( option_pain[i], 1 ), row, 5, rowcolor[i], right ); 
}
    
// Finding the Minimum Pain
temp = SparseCompress(bi<endval, option_pain);
temp = Lowest(temp);
expiry = Ref( SparseCompress(bi<endval,strike), -LowestBars(temp));

SetBarsRequired(endval);// reduce bar requirement

// Draw summary/message row
GfxSelectFont( "Tahoma", 9, 800 ); // Make it bolder
GfxSetTextColor( colorYellow );
PrintSummaryCellC( "Expiry likely to be at " + NumToStr( LastValue(expiry), 1), endval+1, 7 ); // pass the row and the toal of cols used
_SECTION_END();

But once again... there is zero Gfx required to output such table.
Exploration provides any table output easily and quickly and without much hassle.
Do you see how much less work is required?

/// @link https://forum.amibroker.com/t/how-to-change-the-time-axis-to-strike-price-in-amibroker/11708/12
bi = BarIndex();
start = 10600;
strike = start + 50 * bi;
endval = Min(31, BarCount);

call_oi = Max(3, bi * 5 + floor(mtRandomA() * 25));   // TO_REMOVE - Used only to test the formula
put_oi = Max(2, bi * 5 + floor(mtRandomA() * 25));   // TO_REMOVE - Used only to test the formula

// To uncomment
//for ( i = 0; i < endval; i++ ) {
    // call_oi[i] = LastValue( Foreign( "NIFTYWK" + strike[i] + "CE", "I" ) ); // To uncomment
    // put_oi[i] = LastValue( Foreign( "NIFTYWK" + strike[i] + "PE", "I" ) );   // To uncomment      
//}

// Call Pain
rev_strike = (strike - Nz(Ref(strike, -1))) * Nz(Ref(call_oi, -1));
call_pain = SumSince(bi == 0, rev_strike);

// Put Pain
rev_strike = (Ref(strike,1)-strike) * Ref(put_oi,1);
put_pain = Reverse(SumSince(bi==BarCount-endval, Reverse(rev_strike)));

option_pain = call_pain + put_pain;

Filter = bi < endval;

temp = SparseCompress(Filter, option_pain);
temp = Lowest(temp);
expiry = Ref(SparseCompress(Filter,strike), -LowestBars(temp));

colorBlueAlt = ColorRGB( 72, 73, 200 ); // alternative hue of blue
rowColor = IIf( bi % 2, colorDarkBlue, colorBlueAlt );

SetBarsRequired(endval);// reduce bar requirement

SetOption( "NoDefaultColumns", True);
AddRow( "Expiry likely");
AddRow( "to be at " + LastValue(expiry));
AddColumn( strike, "Strike", format = 1, fntcolor = colorWhite, rowColor);
AddColumn( call_oi, "Call OI", format, fntcolor, rowColor);
AddColumn( put_oi, "Put OI", format, fntcolor, rowColor);
AddColumn( call_pain, "Call pain", format, fntcolor, rowColor);
AddColumn( put_pain, "Put pain", format, fntcolor, rowColor);
AddColumn( option_pain, "Option pain", format, fntcolor, rowColor);
AddColumn( put_oi / call_oi, "PCR", format=1.2, fntcolor, rowColor);

31

12 Likes

If you could kindly help me with the AFL of this.

@Ankitpat24,

Only users with "Verified Badge" are allowed to post on this forum. Search "Verified Badge" for more information on how to get verified.

1 Like

Sorry to review the old thread; I have been using this solution for quite a long time; however, recently, I was trying to access the strike for a call and put based on the highest OI, so far I can get the highest OI individually (Call Or Put) as per below snippet logic.

CallOIShort = Sort( call_oi, 0, endval, True );
HighestCallOI = NumToStr( call_oi[CallOIShort[endval]], 1 );
//_TRACE("HighestCallOI : " + HighestCallOI);

However, I cannot get the respective strike of the Highest OI when I use SparseCompress here as per the below snippet.

CallStrike = Ref( SparseCompress( bi < endval, strike ), -LowestBars( StrToNum(HighestCallOI) ) );

I am sure logically, somewhere, I am missing something but unable to figure it out.

Anyway, I have found the solution for my above query as below.

HighestCallOI = SparseCompress( bi < endval, Call_OI );
HighestCallOI = Highest(HighestCallOI);
CallStrike = Ref( SparseCompress( bi < endval, strike ), -HighestBars(HighestCallOI) );
1 Like

@fxshrat, Is it possible for you to share the AFL code for the above image {Nifty option chain: Change in open interest).? I need exactly the above one, I have written some AFLs based on the time axis (plots function) but I need to write some AFLs based on other references (Strike price, etc..) for live analysis.

Thanks for all your posts