We are using the WebSocket feed for real-time data, specifically subscribing to instruments like NSE_FO|62401. However, despite trades actively happening on these instruments (confirmed via the terminal), we are receiving LTT values from previous days.
Example:
Instrument: NSE_FO|62401
Received LTP: 153.9
Received LTT: 2025-06-20 15:29:59
Received At: 2025-06-23 11:05:18
Difference: ~243318 seconds
This stale LTT is causing us to skip live ticks. Even after reconnecting and resubscribing, the issue persists.
Please confirm if this is a known delay, and advise how we can ensure real-time ticks are received properly.
@Ketan
Please check the Github Code,
are you saying API version is need to update??
function fetchMarketUpdates()
{
$apiVersion = â2.0â;
$accessToken = âACCESS_TOKENâ;
// Configure with your access token
$configuration = Configuration::getDefaultConfiguration();
$configuration->setAccessToken($accessToken);
// Get the authorized URL for the WebSocket connection
$response = getMarketDataFeedAuthorize($apiVersion, $configuration);
$connection = connect($response['data']['authorized_redirect_uri']);
echo "Connection successful!\n";
// Message payload to send to the server
$data = [
"guid" => "someguid",
"method" => "sub",
"data" => [
"mode" => "full",
"instrumentKeys" => ["NSE_INDEX|Nifty Bank", "NSE_INDEX|Nifty 50"]
]
];
// Send the data as binary
$binaryData = json_encode($data);
$connection->sendBinary($binaryData);
foreach ($connection as $message) {
$payload = $message->buffer();
if ($payload === '100') {
$connection->close();
break;
}
if (!empty($payload)) {
$decodedData = decodeProtobuf($payload);
// Convert the decoded data to JSON and print it
var_dump($decodedData->serializeToJsonString());
}
}
I have few more question on API v2.
As we are creating access-token using api version v2 will that Affect while creating Authorization Url?
wss://wsfeeder-api.upstox.com/market-data-feeder/v2/upstox-developer-api/feeds?requestId=e60e481b-ac3d-432b-8e00-aedd59fa7454&code=xHCw0-0d1495b3-b084-49dc-94bb-d9f9093da484
@HritikRD
Changing the API version wonât helpâyou need to change the function youâre calling. Please use getMarketDataFeedAuthorizeV3 instead of getMarketDataFeedAuthorize.
If youâre using an older version of the PHP SDK, this function may not be available. You can switch to the latest version, which is 1.17.
[2025-06-25 12:35:06] local.INFO: SKIPPED stale tick for NSE_EQ|INE919I01024: LTP=9.2, LTT=2025-06-25 12:34:17 (diff: 48s)
[2025-06-25 12:35:06] local.INFO: SKIPPED stale tick for NSE_EQ|INE642Y01029: LTP=35.1, LTT=2025-06-25 12:33:35 (diff: 90s)
[2025-06-25 12:35:06] local.INFO: SKIPPED stale tick for NSE_EQ|INE414D01027: LTP=294.7, LTT=2025-06-25 12:33:10 (diff: 115s)
[2025-06-25 12:35:06] local.INFO: SKIPPED stale tick for NSE_EQ|INE634I01029: LTP=213.69, LTT=2025-06-25 12:34:08 (diff: 58s)
[2025-06-25 12:35:06] local.INFO: SKIPPED stale tick for NSE_EQ|INF204KC1022: LTP=130.87, LTT=2025-06-25 12:33:34 (diff: 91s)
[2025-06-25 12:35:06] local.INFO: SKIPPED stale tick for NSE_EQ|INE350C01017: LTP=652.35, LTT=2025-06-25 12:33:32 (diff: 93s)
But the Prices of this stoks are higher and different , compared to current time i,e ,12.35 pm
It seems sometimes the Websocket is providing Old values.
How to tackle this.
The Short PHP Code i written
$apiVersion = â3.0â;
$accessToken = $bearerToken;
// Configure with your access token
$configuration = Configuration::getDefaultConfiguration();
$configuration->setAccessToken($accessToken);
// Get the authorized URL for the WebSocket connection
$response = $this->getMarketDataFeedAuthorizeV3($apiVersion, $configuration);
$connection = connect($response['data']['authorized_redirect_uri']);
// Fetch buy/sell data of recommendations
$getBuySellDataOfRecommendations = ManageRecommendation::select('id', 'instrument_key', 'recommendation_actions_xid')
->whereIn('recommendation_actions_xid', [1, 2, 3])
->where('product_type_xid', 1) //only for tradeoptions
->orderByDesc('id')
->get();
// Create a mapping of instrument_key to recommendation_id
$instrumentKeyMap = [];
foreach ($getBuySellDataOfRecommendations as $recommendation) {
if ($recommendation->schedule_date_time < $currentDateTime->format('Y-m-d H:i:s') || $recommendation->schedule_date_time == null) {
$instrumentKeyMap[$recommendation->instrument_key] = $recommendation->id;
}
}
// Extract instrument keys
$instrumentKeys = array_keys($instrumentKeyMap);
if (empty($instrumentKeys)) {
Log::warning('No valid instrument keys found. Aborting WebSocket connection. In OPTIONS');
return;
}
// Message payload to send to the server
$data = [
"guid" => uniqid('guid_', true),
"method" => "sub",
"data" => [
"mode" => "full",
"instrumentKeys" => $instrumentKeys
]
];
// Send the data as binary
$binaryData = json_encode($data);
$connection->sendBinary($binaryData);
// Define stop time (4:00 PM)
// $stopTime = now()->setTime(19, 9);
foreach ($connection as $message) {
$payload = $message->buffer();
usleep(2000000);
if ($payload === '100') {
$connection->close();
break;
}
if (!empty($payload)) {
$decodedData = $this->decodeProtobuf($payload);
$jsonData = json_decode($decodedData->serializeToJsonString(), true);
if (empty($jsonData['feeds'])) {
Log::info('No feed data found in payload IN TRADE OPTION');
continue;
}
// Log::info("Trade Options running");
foreach ($jsonData['feeds'] as $instrumentKey => $instrumentData) {
// Get the recommendation ID using the instrument_key
$recommendationId = $instrumentKeyMap[$instrumentKey] ?? null;
if ($recommendationId && isset($instrumentData['ff']['marketFF']['ltpc']['ltp'])) {
$ltp = $instrumentData['ff']['marketFF']['ltpc']['ltp'];
$lttMs = $instrumentData['ff']['marketFF']['ltpc']['ltt'] ?? null;
// Convert LTT to Carbon instance
if ($lttMs) {
$lttTimestamp = (int) ($instrumentData['ff']['marketFF']['ltpc']['ltt'] ?? 0);
$lttCarbon = Carbon::createFromTimestampMs($lttTimestamp);
$now = now();
$diffInSeconds = $now->diffInSeconds($lttCarbon);
if ($diffInSeconds > 50) {
Log::info("SKIPPED stale tick for {$instrumentKey}: LTP={$ltp}, LTT={$lttCarbon} (diff: {$diffInSeconds}s)");
continue;
}
}
$lastTradedPrice = $ltp;
$range = $getBuySellDataOfRecommendationItem->buy_price;
// Log::info($recommendationId . '-' . $lastTradedPrice . '-' . $range);
Log::info("RECEIVED: {$recommendationId}-{$ltp}-{$range}-LTT={$lttCarbon->toDateTimeString()}");
// Check if lastTradedPrice falls within the range
} else {
Log::error("LTP not found for Instrument Key: $instrumentKey (Recommendation ID: $recommendationId)");
}
}
}
}
@HritikRD
Currently, the V3 WebSocket does not provide a live feed. Instead, it delivers the previous minuteâs data, and you are expected to construct the current feed using the LTP (Last Traded Price) updates received from the WebSocket.
To support a higher number of instrument subscriptions per connection, weâve optimized the data payload by sending reduced data per instrument key. This ensures efficient usage of network bandwidth on both the client and server sides
We have forwarded this concern to the appropriate team.