How to Create Ticker-Like Custom Pairs in AmiBroker with Real-Time Updates

Purpose

I wish to execute a stock pairs trading strategy, where I need to track a specific list of 50 stock pairs simultaneously, in real-time while maintaining 1 year of historical data of the pairs in 1 minute candlestick format.

My method for creating Pair's Spread

Pairs are calculated using a simple rolling regression to find the hedge ratio and spread calculation use a simple y=mx formula where m is the hedge ratio, it is very crucial for me to at least update this hedge ratio every minute.

Goal

  1. Real-time updates with ≤ 200 MS latency.
  2. Full ticker-like behavior for custom pairs.
  3. Preloaded 1-year historical data with real-time backfilling (The 50 Spreads should backfill, update within a minute as soon as the tickers are backfilled contributing to the spreads).
  4. Custom symbols named ~Symbol1_Symbol2.
  5. Must use a registered data feed like IQ Feed or the IB plugin Feed.

Done So Far & Challenges Faced

Out of all the possible paths available in Amibroker, given my proficiency level I could come up with the following solution this is where I need specific help, as to is there a path that is more robust that I have missed

  • I tried to achieve this through AddToComposite but it recalculates history repeatedly on every iteration, slowing everything down and my updation happens after 15 seconds rather than the desired 200 MS , I tried running it in indicator mode as well as repeated explorations but soon realized that I picked the wrong tool for my use case or probably have a lapse in my understanding.
  • Static Variables don’t allow seamless ticker-like behavior. So, it’s a no go for me as most of the great seamless functionalities Amibroker provides on tickers won’t be so straightforward for me given my expertise using staticvariables.
  • Also cant use formula files (via spread indicator) as pairs are required as tickers for complete functionality.
  • I’m not proficient in C++ to create a custom plugin and want to build on the existing IB data feed or any other registered robust data feed that has handled the stock data properly, so I have a solid base without reinventing anything.

I apologise in advance if my problem statement is coming from lack of understanding of the basics as i am still getting familiar with Amibroker as its a really robust vast Software.

Below is my sample code that I implemented using AddtoComposite() to be run in scan mode repeatedly to keep the pairs updated.

y="PETRONET,IOC,"+
"TORNTPOWER,POWERGRID,"+
"TORNTPOWER,NTPC,"+
"TORNTPOWER,TATAPOWER,"+
"TORNTPOWER,IEX,"+
"POWERGRID,NTPC,"+
"POWERGRID,TATAPOWER,"+
"POWERGRID,IEX,"+
"NTPC,TATAPOWER,"+
"NTPC,IEX,"+
"TATAPOWER,IEX,"+
"GODREJPROP,DLF,"+
"GODREJPROP,OBEROIRLTY,"+
"DLF,OBEROIRLTY,"+
"TRENT,ABFRL,"+
"IDEA,INDUSTOWER,"+
"IDEA,TATACOMM,"+
"IDEA,BHARTIARTL,"+
"INDUSTOWER,TATACOMM,"+
"INDUSTOWER,BHARTIARTL,"+
"TATACOMM,BHARTIARTL";

for(i=0;i<StrLen(y);i+=2)
{
	symbol_1 = StrExtract(y,i);
	symbol_2 = StrExtract(y,i+1);

lookback_linearreg = 1500;
///////////////////////////////Symbol_import 
//_N( Symbol_1= ParamStr("Symbol1", symbol_1) );
c1 = log(Foreign(symbol_1,"C"));
c2 = log(Foreign(symbol_2,"C"));
xy = c1*c2 ;
x2 = c1*c1 ;
y2 = c2*c2 ;

slope = 1/((Sum(xy,lookback_linearreg) - (Sum(c1 , lookback_linearreg)*Sum(c2,lookback_linearreg)))/
(Sum(x2, lookback_linearreg)-(Sum(c1,lookback_linearreg)*Sum(c1,lookback_linearreg))));

spread = (10+(c1 - (slope*c2)));

// calculating the spread 

tickerspread = "~"+symbol_1+"_"+symbol_2;

AddToComposite(spread, tickerspread, "X", atcFlagDefaults);
AddToComposite(slope, tickerspread, "1", atcFlagDefaults);


Filter = 1 ;

}```

Using AddToComposite doesn't make too much sense as this function isn't meant for such purpose. Instead remove AddToComposite and just use Plot( slope....) directly in that formula. This way you will get no latency.

I am sorry probably I don't understand the full capabilities of Amibroker plot function , how will that create Custom Tickers of Pairs which AddToComposite does ?

For better understanding , I am sharing screenshots of 2 different stock pairs,

I make a pair using rolling linear regression in one minute time interval using the last 1500 values , I navigate through them using a navigation pane as seen on the left in the screenshot.

How can I achieve the same in Amibroker using a Realtime Data feed , For 50 different pairs listed on the left as symbols in the Amibroker navigation pane being updated in Realtime.

Find the screenshots below :-


This code plots the simple spread between 2 stocks and updates prices in real time:

symbol1 = "MSFT";
symbol2 = "GOOGL";

// retrieve symbol2 prices
SetForeign( Symbol2 );
C2 = C; 
H2 = H; 
L2 = L; 
O2 = O; 
RestorePriceArrays();

//Spread
spread = C-C2; 
Plot(spread,"Spread",colorRed,styleOwnScale|styleThick);

// check if ticker selected is ok
if( Name() != symbol1 AND Name() != symbol2 )  
{ 	GfxSetBkColor( colorOrange); GfxSelectFont( "Tahoma", 20 );   
	GfxSetBkMode( 2 ); GfxTextOut("SELECT: "+symbol1+" or "+symbol2, 40, 20 ); 
}

For storing stock pairs you can use individual watchlists:

if( InWatchListName("pair1") ) { symbol1 = "MSFT"; symbol2 = "GOOGL"; }

And you can use static vars the following way to avoid mixing symbols from other pairs:

StaticVarSetText("PairOf" + symbol1, symbol2);
StaticVarSetText("PairOf" + symbol2, symbol1);

You just don't need to create anything. Just use foreign directly in the formula. This "creation" process you are insisting on doesn't bring any benefit. Composites are useful when you want to create composite indicators from hundreds or thousands of different securities.

For symbol pairs it makes no sense. Just use Foreign. Take your code eliminate all composites and stuff. Just take the calculation and plut it.

// YOUR CALCULATION HERE
c1 = log(Foreign(symbol_1,"C"));
c2 = log(Foreign(symbol_2,"C"));
xy = c1*c2 ;
x2 = c1*c1 ;
y2 = c2*c2 ;

slope = 1/((Sum(xy,lookback_linearreg) - (Sum(c1 , lookback_linearreg)*Sum(c2,lookback_linearreg)))/
(Sum(x2, lookback_linearreg)-(Sum(c1,lookback_linearreg)*Sum(c1,lookback_linearreg))));

spread = (10+(c1 - (slope*c2)));

// don't create composite !! Just plot

Plot( spread, "Spread", colorDefault );
Plot( slope, "Slope", colorDefault, styleOwnScale );

Or better yet, use CURRENT SYMBOL data as one of the symbols in your calculation and just ONE foreign call. This is FASTER than any other solution

// YOUR CALCULATION HERE
c1 = log( Close ) ; // USE CURRENT SYMBOL CLOSE INSTEAD OF Foreign(symbol_1,"C"));
c2 = log(Foreign(symbol_2,"C"));
xy = c1*c2 ;
x2 = c1*c1 ;
y2 = c2*c2 ;

slope = 1/((Sum(xy,lookback_linearreg) - (Sum(c1 , lookback_linearreg)*Sum(c2,lookback_linearreg)))/
(Sum(x2, lookback_linearreg)-(Sum(c1,lookback_linearreg)*Sum(c1,lookback_linearreg))));

spread = (10+(c1 - (slope*c2)));

// don't create composite !! Just plot

Plot( spread, "Spread", colorDefault );
Plot( slope, "Slope", colorDefault, styleOwnScale );