ODIN Price Feed API
ODIN Price Feed API • Web Feed Handler

Modern real-time market data for web and desktop apps

Connect over WebSocket or secure WebSocket, subscribe to touchline and best-five streams, and render low-latency market data with a polished developer-first workflow.

Mode WS / WSS Transport Compressed binary stream Use case Live market watchlists
Explore the interactive API guide
Use the live controls below to connect, subscribe, and validate response payloads in real time.

Fast connect

Configure the host, port, and credentials, then connect to the feed in one click.

Subscription flow

Send touchline and best-five requests using the provided request formats and live examples.

Response view

Inspect connection status, decoded packets, and implementation snippets from the same page.

ODIN Price Feed API or Web Feed Handler API (internal name) allows the developer to fetch the price related information like last traded price, Touch Line, Best Five etc. The Price Feed API communicates to applications on TCP/Web Socket connection using subscription model and data is transmitted in a compressed mode.

WFH API can be used to display following information on any mobile or web application.

  • Multiple Touchline
  • Best Five

This step-by- step guide will assist you through the entire flow of API implementation; right from authentication, to handle the request and response structure of the API.

 WS    WSS
SEND MESSAGE
CONNECTION STATUS
  
RESPONSE MESSAGE
CONNECT CODE
   function ConnectSocket(mode,ip,port){
	try
	{
		objSocket = null;
		
		objSocket = new WebSocket(mode + '://' + ip + ':' + port);		
		objSocket.binaryType = 'arraybuffer';

		objSocket.onopen = socketOnOpen;
		objSocket.onclose = socketOnClose;
		objSocket.onerror = socketOnError;
		objSocket.onmessage = socketOnMessage;
		
	}	
	catch(ex)
	{
		
	}
}

socketOnOpen = function(){
	
	var sUsedId = 'TEST';
	
	
	var sLoginRequest ="63=FT3.0|64=101|65=74|66=14:59:22|67=TEST|68=YOUR_API_KEY|4=|400=0|401=2|396=HO|51=4|395=127.0.0.1";
	SendMessageOnSocket((sLoginRequest));
}

function SendMessageOnSocket(msg){

	try
	{
		if(objSocket.readyState == 1)
		{
			objSocket.send(fragmentData(msg));

		}
		
	}
	catch(ex)
	{
		
	}

}

 function fragmentData(_requestPacket) {
       
        try {						
			
            
                var _strHead = _strHead = String.fromCharCode('5'); //5 comprression char
                

                var i;
                var _data = new ArrayBuffer(_strHead.length);
                var _headerBytes = new Uint8Array(_data);

                for (i = 0; i < _strHead.length; i += 1) {
                    _headerBytes[i] = _strHead.charCodeAt(i);
                }
                var _baRequest;
                _baRequest = HandleCompressedData(_requestPacket);
                

                var _length = _baRequest.length + 4;
                
                var _lenLength = _length.toString().length;
                var _lengthString = "";

                for (i = 0; i < (5 - _lenLength); i++) {
                    _lengthString += "0";
                }

                _lengthString += _length.toString();

                _data = new ArrayBuffer(_lengthString.length);
                var _lenBytes = new Uint8Array(_data);

                for (i = 0; i < _lengthString.length; i += 1) {
                    _lenBytes[i] = _lengthString.charCodeAt(i);
                }

                var _baActualSend = new Uint8Array(5 + _length);
                _baActualSend.set(_lenBytes);
                _baActualSend.set(_baRequest, 5);

                var _outputStream = new Uint8Array(_headerBytes.length + _baActualSend.length);
                _outputStream.set(_headerBytes);
                _outputStream.set(_baActualSend, 1);
                return _outputStream.buffer;
            
        }
        catch (e) 
				{
            
        }
    };
    
    function	HandleCompressedData(_rawData) {
        
        try {
            var _data = new ArrayBuffer(_rawData.length);
            var _uint8buf = new Uint8Array(_data);
            for (var i = 0; i < _rawData.length; i += 1) {
                _uint8buf[i] = _rawData.charCodeAt(i) & 0xFF;
            }
            
            var _compData = Zlib.compress(new Uint8Array(_data), 6);
            
            return _compData;
        }
        catch (e) 
				{
           
        }
    };

   
RECIEVE CODE


	function socketOnMessage(_event){
	
	try
	{
						var baProcessData = null;
            var intRawPktLen;
            var intCompLen = 0;
            var _response, isBroken = false;
            var totalPacketLength = 0;

            if (_event.data instanceof ArrayBuffer) {

                var dataReceived = null;
                var dataPacketLengthList = [];
                if (baOldData == null)
                    dataReceived = new Uint8Array(_event.data);
                else {
                    dataReceived = AppendOrCopyBuffer(baOldData, _event.data);
                    baOldData = null;
                }

                intRawPktLen = dataReceived.byteLength;
                var i = 0;
                if (intRawPktLen > 5) {
                    while (i < intRawPktLen) {
                        if (dataReceived[i] == 5 || dataReceived[i] == 2) {
                            var strPacketLength = String.fromCharCode.apply(null, dataReceived.subarray(i + 1, i + 6));
                            if (strPacketLength.length == 5) {
                                var packetLength = parseInt(strPacketLength, 10);
                                dataPacketLengthList.push(packetLength + 6);
                                totalPacketLength += packetLength + 6;
                                i = i + 6 + packetLength;
                            }
                            else {
                                baOldData = dataReceived.subarray(i, intRawPktLen);
                                isBroken = true;
                                break;
                            }
                        }
                        
                    }
                }
                else 
                    baOldData = dataReceived;
               
                if (intRawPktLen == totalPacketLength) {
                    // split and pass to zlib to uncompress
                    for (var i = 0, j = 0, k = dataPacketLengthList[0], len = dataPacketLengthList.length; i < len ; i++) {

                        var uncompData = dataReceived.subarray(j, k);
                        ProcessSocketMessage(uncompData);

                        j = k;
                        k = k + dataPacketLengthList[i + 1];
                    }
                    baOldData = null;
                }
                else {
                    var i = 0, j = 0;
                    var k = (dataPacketLengthList.length > 0 ? dataPacketLengthList[0] : 0);

                    if (!isBroken) {
                        for (var len = dataPacketLengthList.length ; i < len - 1; i++) {
                            var uncompData = dataReceived.subarray(j, k);
                            ProcessSocketMessage(uncompData);

                            j = k;
                            k = k + dataPacketLengthList[i + 1];
                        }

                        if (i == dataPacketLengthList.length - 1) {
                            baOldData = null;
                            baOldData = dataReceived.subarray(j, k);
                            if (baOldData[0] != 5 && baOldData[0] != 2)  
                                alert();
                        }
                        
                    }
                    else {
                        for (var len = dataPacketLengthList.length; i < len; i++) {
                            var uncompData = dataReceived.subarray(j, k);
                            ProcessSocketMessage(uncompData);

                            j = k;
                            k = k + dataPacketLengthList[i + 1];
                        }
                        isBroken = false;
                    }
                }
            }
           
		
	}
	catch(ex)
	{
		
	}

}

function ProcessSocketMessage(uncompData) {
         _response = DeCompressData(uncompData);

        if (_response == undefined) {
            console.log(_response);
        }
        //remove End of response char
        var intTmtrIndex = _response.indexOf('\u0000');
        if (intTmtrIndex != -1) {
            _response = _response.substr(0, intTmtrIndex);
        }

        //split multi response packet with Start of response char C_S_CHAR2  
        var arrData = _response.split("\u0002");
        var intDataCount = arrData.length;

        for (var intDataCntr = 0; intDataCntr < intDataCount; intDataCntr++) {
            if (arrData[intDataCntr] != "") {
                console.log("Packet: " + arrData[intDataCntr]);
            }
        }
    }

    
Touchline Req (Token_MarketSegment):

		var sMsg ='',sMsgToSend ='';
		sMsg = 1_22,1_2885;
		var sTokenArr = sMsg.split(',')
		sMsgToSend = "63=FT3.0|64=206|65=84|66=19:02:31|4=|";
		 
		for(var i=0;i < sTokenArr.length;i++)
		{
			sMsgToSend += "1=" + (sTokenArr[i].split('_')[0]) + "$7=" + sTokenArr[i].split('_')[1] + "|";
		}
		sMsgToSend += "230=1";
		
		//Sample String Generated: = 63=FT3.0|64=206|65=84|66=19:02:31|1=1$7=22|1=1$7=2885|230=1
		
		SendMessageOnSocket(sMsgToSend);
		


	function SendMessageOnSocket(msg){
	
		try
		{
			if(objSocket.readyState == 1)
			{
				objSocket.send(fragmentData(msg));
	
			}
			
		}
		catch(ex)
		{
			
		}
	
	}

 function fragmentData(_requestPacket) {
       
  try {
  
          var _strHead = _strHead = String.fromCharCode('5'); //5 comprression char
          

          var i;
          var _data = new ArrayBuffer(_strHead.length);
          var _headerBytes = new Uint8Array(_data);

          for (i = 0; i < _strHead.length; i += 1) {
              _headerBytes[i] = _strHead.charCodeAt(i);
          }
          var _baRequest;
          _baRequest = HandleCompressedData(_requestPacket);
          

          var _length = _baRequest.length + 4;
          
          var _lenLength = _length.toString().length;
          var _lengthString = "";

          for (i = 0; i < (5 - _lenLength); i++) {
              _lengthString += "0";
          }

          _lengthString += _length.toString();

          _data = new ArrayBuffer(_lengthString.length);
          var _lenBytes = new Uint8Array(_data);

          for (i = 0; i < _lengthString.length; i += 1) {
              _lenBytes[i] = _lengthString.charCodeAt(i);
          }

          var _baActualSend = new Uint8Array(5 + _length);
          _baActualSend.set(_lenBytes);
          _baActualSend.set(_baRequest, 5);

          var _outputStream = new Uint8Array(_headerBytes.length + _baActualSend.length);
          _outputStream.set(_headerBytes);
          _outputStream.set(_baActualSend, 1);
          return _outputStream.buffer;
            
        }
        catch (e) 
				{
            
        }
    };
    
    function	HandleCompressedData(_rawData) {
        
        try {
            var _data = new ArrayBuffer(_rawData.length);
            var _uint8buf = new Uint8Array(_data);
            for (var i = 0; i < _rawData.length; i += 1) {
                _uint8buf[i] = _rawData.charCodeAt(i) & 0xFF;
            }
            
            var _compData = Zlib.compress(new Uint8Array(_data), 6);
            
            return _compData;
        }
        catch (e) 
				{
           
        }
    };

    
Best Five Req (Token_MarketSegment):

		var sMsg ='',sMsgToSend ='';
		sMsg = 1_22;
		
	  sMsgToSend = "63=FT3.0|64=127|65=84|66=19:02:31|1=" + (sMsg.split('_')[0]) + "|7=" + sMsg.split('_')[1] + "|230=1";
		
		//Sample String Generated: = 63=FT3.0|64=127|65=84|66=19:02:31|1=1|7=22|230=1
		
		SendMessageOnSocket(sMsgToSend);
		


function SendMessageOnSocket(msg){

	try
	{
		if(objSocket.readyState == 1)
		{
			objSocket.send(fragmentData(msg));

		}
		
	}
	catch(ex)
	{
		
	}

}

 function fragmentData(_requestPacket) {
       
        try {						
			
            
                var _strHead = _strHead = String.fromCharCode('5'); //5 comprression char
                

                var i;
                var _data = new ArrayBuffer(_strHead.length);
                var _headerBytes = new Uint8Array(_data);

                for (i = 0; i < _strHead.length; i += 1) {
                    _headerBytes[i] = _strHead.charCodeAt(i);
                }
                var _baRequest;
                _baRequest = HandleCompressedData(_requestPacket);
                

                var _length = _baRequest.length + 4;
                
                var _lenLength = _length.toString().length;
                var _lengthString = "";

                for (i = 0; i < (5 - _lenLength); i++) {
                    _lengthString += "0";
                }

                _lengthString += _length.toString();

                _data = new ArrayBuffer(_lengthString.length);
                var _lenBytes = new Uint8Array(_data);

                for (i = 0; i < _lengthString.length; i += 1) {
                    _lenBytes[i] = _lengthString.charCodeAt(i);
                }

                var _baActualSend = new Uint8Array(5 + _length);
                _baActualSend.set(_lenBytes);
                _baActualSend.set(_baRequest, 5);

                var _outputStream = new Uint8Array(_headerBytes.length + _baActualSend.length);
                _outputStream.set(_headerBytes);
                _outputStream.set(_baActualSend, 1);
                return _outputStream.buffer;
            
        }
        catch (e) 
				{
            
        }
    };
    
    function	HandleCompressedData(_rawData) {
        
        try {
            var _data = new ArrayBuffer(_rawData.length);
            var _uint8buf = new Uint8Array(_data);
            for (var i = 0; i < _rawData.length; i += 1) {
                _uint8buf[i] = _rawData.charCodeAt(i) & 0xFF;
            }
            
            var _compData = Zlib.compress(new Uint8Array(_data), 6);
            
            return _compData;
        }
        catch (e) 
				{
           
        }
    };