Hello @sajos
This looks like error in the Java application that you have written. We have sample code in Python, if you want to use that as reference.
Hello @sajos
This looks like error in the Java application that you have written. We have sample code in Python, if you want to use that as reference.
@Hardik ,
The message "Invalid Input Parameters"
is coming from the server, not from Java code.
Context of handleTextMessage
: The handleTextMessage
method is springboot implementation of WebSocketHandler to receive and handle messages sent from the WebSocket server.
Hello @sajos
Can you check the authorisation here then, are you on V1 or V2 while connecting to socket?
Heyy
you can try extending WebsocketClient
@Override
public void onOpen(ServerHandshake handshake) {
if(feedRequest == null) {
// Feed request example (subscribe to NSE segment and specific scrip)
feedRequest = "{\r\n"
+ " \"RequestCode\" : 15,\r\n"
+ " \"InstrumentCount\" : 2,\r\n"
+ " \"InstrumentList\" : [\r\n"
+ " {\r\n"
+ " \"ExchangeSegment\" : \"NSE_EQ\",\r\n"
+ " \"SecurityId\" : \"1333\"\r\n"
+ " },\r\n"
+ " {\r\n"
+ " \"ExchangeSegment\" : \"BSE_EQ\",\r\n"
+ " \"SecurityId\" : \"532540\"\r\n"
+ " }\r\n"
+ " ]\r\n"
+ "}\r\n"
+ "";
send(feedRequest);
System.out.println("Connected to WebSocket server with Test Json.");
System.out.println("Sent feed request: " + feedRequest);
}else {
send(feedRequest);
System.out.println("Connected to WebSocket server with Passed Json.");
System.out.println("Sent feed request: " + feedRequest);
}
}
@Override
public void onMessage(ByteBuffer bytes) {
TickerData tickerData = parseTickerData(bytes);
System.out.println(tickerData);
}
and Thanks your code really help me.
Hi @Hardik and @rahulbajaj,
Thank you for your clarifications; my code is now working.
The issue was due to a mistake while updating the new token. I missed the &token
parameter name when updating it, which caused the âInvalid input parametersâ error.
Below is the working code for Version 2 for others to refer to if they encounter any issues.
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.web.socket.BinaryMessage;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.client.WebSocketConnectionManager;
import org.springframework.web.socket.client.standard.StandardWebSocketClient;
import org.springframework.web.socket.handler.AbstractWebSocketHandler;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.text.DecimalFormat;
import java.time.Instant;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.*;
@SpringBootApplication
public class TradingApplication {
// Define client ID, token, and request code as static variables
private static final String CLIENT_ID = "xxxxxxx";
private static final String TOKEN = "xxxxxxxx";
public static void main(String[] args) {
SpringApplication.run(TradingApplication.class, args);
}
@Bean
public WebSocketConnectionManager connectionManager() {
StandardWebSocketClient client = new StandardWebSocketClient();
DhanWebSocketHandler handler = new DhanWebSocketHandler();
String url = "wss://api-feed.dhan.co?version=2"
+ "&token=" + TOKEN
+ "&clientId=" + CLIENT_ID
+ "&authType=2";
WebSocketConnectionManager manager = new WebSocketConnectionManager(client, handler, url);
manager.setAutoStartup(true);
return manager;
}
}
// A class for handling WebSocket communication and subscription messages
class DhanWebSocketHandler extends AbstractWebSocketHandler {
private static final int MAX_INSTRUMENTS_PER_REQUEST = 100;
private static final int REQUEST_CODE = 15;
// Static map for instrument information with Security ID as the key
private static final Map<String, InstrumentInfo> INSTRUMENTS = new LinkedHashMap<>();
static {
INSTRUMENTS.put("1333", new InstrumentInfo("HDFCBANK", "1333", "NSE_EQ"));//NSE stock
INSTRUMENTS.put("532540", new InstrumentInfo("TCS", "532540", "BSE_EQ"));//BSE stock
INSTRUMENTS.put("19237", new InstrumentInfo("MONIFTY500", "19237", "NSE_EQ"));//Motilal Oswal Nifty 500 ETF
INSTRUMENTS.put("25", new InstrumentInfo("BANKNIFTY", "25", "IDX_I"));//Index
INSTRUMENTS.put("43972", new InstrumentInfo("NIFTY 14 NOV 24500 CALL", "43972", "NSE_FNO"));//Options
// Add more instruments as needed
}
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
System.out.println("Connected to Dhan WebSocket");
sendSubscriptionMessages(session);
}
private void sendSubscriptionMessages(WebSocketSession session) throws Exception {
List<Map.Entry<String, InstrumentInfo>> instrumentList = new ArrayList<>(INSTRUMENTS.entrySet());
for (int i = 0; i < instrumentList.size(); i += MAX_INSTRUMENTS_PER_REQUEST) {
int end = Math.min(i + MAX_INSTRUMENTS_PER_REQUEST, instrumentList.size());
List<Map.Entry<String, InstrumentInfo>> batch = instrumentList.subList(i, end);
String subscriptionMessage = createSubscriptionMessage(batch);
session.sendMessage(new TextMessage(subscriptionMessage));
System.out.println("Sent subscription request for batch: " + (i / MAX_INSTRUMENTS_PER_REQUEST + 1));
}
}
private String createSubscriptionMessage(List<Map.Entry<String, InstrumentInfo>> instruments) {
StringBuilder instrumentListJson = new StringBuilder();
for (Map.Entry<String, InstrumentInfo> entry : instruments) {
InstrumentInfo info = entry.getValue();
instrumentListJson.append("{\"ExchangeSegment\": \"").append(info.getExchangeSegment())
.append("\", \"SecurityId\": \"").append(entry.getKey()).append("\"},");
}
// Remove trailing comma
if (instrumentListJson.length() > 0) {
instrumentListJson.setLength(instrumentListJson.length() - 1);
}
return "{"
+ "\"RequestCode\": " + REQUEST_CODE + ","
+ "\"InstrumentCount\": " + instruments.size() + ","
+ "\"InstrumentList\": [" + instrumentListJson + "]"
+ "}";
}
@Override
protected void handleBinaryMessage(WebSocketSession session, BinaryMessage message) throws Exception {
ByteBuffer byteBuffer = message.getPayload();
byteBuffer.order(ByteOrder.LITTLE_ENDIAN); // Set byte order if required by API
byte[] responseHeader = new byte[8];
byteBuffer.get(responseHeader);
byte feedResponseCode = responseHeader[0];
if (feedResponseCode == 50) {
short disconnectCode = byteBuffer.getShort();
System.out.println("Disconnection Code: " + disconnectCode);
} else if (feedResponseCode == 2) {
String securityId = extractSecurityId(responseHeader);
String instrumentName = INSTRUMENTS.get(securityId).getInstrumentName();
PacketParser.parseTickerPacket(byteBuffer, instrumentName);
}
}
private String extractSecurityId(byte[] responseHeader) {
// Extract the Security ID from the header
return String.valueOf(ByteBuffer.wrap(responseHeader, 4, 4).order(ByteOrder.LITTLE_ENDIAN).getInt());
}
@Override
public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
System.err.println("Error: " + exception.getMessage());
}
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
System.out.println("Connection closed.");
}
}
// A helper class to store instrument information
class InstrumentInfo {
private final String instrumentName;
private final String exchangeSegment;
private final String securityId;
public InstrumentInfo(String instrumentName, String securityId, String exchangeSegment) {
this.instrumentName = instrumentName;
this.securityId = securityId;
this.exchangeSegment = exchangeSegment;
}
public String getInstrumentName() {
return instrumentName;
}
public String getExchangeSegment() {
return exchangeSegment;
}
public String getSecurityId() {
return securityId;
}
}
// A separate class for parsing packets
class PacketParser {
private static final DecimalFormat priceFormat = new DecimalFormat("#.##");
private static final DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
.withZone(ZoneId.systemDefault());
public static void parseTickerPacket(ByteBuffer byteBuffer, String instrumentName) {
float lastTradedPrice = byteBuffer.getFloat();
int lastTradeTime = byteBuffer.getInt();
String formattedDate = formatTradeTime(lastTradeTime);
System.out.println("Instrument: " + instrumentName + ", Last Traded Price: " + priceFormat.format(lastTradedPrice) +
", Last Trade Time: " + formattedDate);
}
private static String formatTradeTime(int lastTradeTime) {
Instant instant = Instant.ofEpochMilli((long) lastTradeTime * 1000);
return dateFormatter.format(instant);
}
}
Output:
Connected to Dhan WebSocket
Sent subscription request for batch: 1
e[2m2024-11-12T12:25:49.975+05:30e[0;39m e[32m INFOe[0;39m e[35m11460e[0;39m e[2m---e[0;39m e[2m[tradingapp] [cTaskExecutor-1]e[0;39m e[2me[0;39me[36mo.s.w.s.c.WebSocketConnectionManager e[0;39m e[2m:e[0;39m Successfully connected
Instrument: HDFCBANK, Last Traded Price: 1740, Last Trade Time: 2024-11-12 17:55:49
Instrument: TCS, Last Traded Price: 4190, Last Trade Time: 2024-11-12 17:55:32
Instrument: MONIFTY500, Last Traded Price: 23, Last Trade Time: 2024-11-12 17:54:34
Instrument: BANKNIFTY, Last Traded Price: 51717.2, Last Trade Time: 2024-11-12 17:55:49
Instrument: NIFTY 14 NOV 24500 CALL, Last Traded Price: 12.85, Last Trade Time: 2024-11-12 17:55:48
Instrument: BANKNIFTY, Last Traded Price: 51714.35, Last Trade Time: 2024-11-12 17:55:49
Instrument: NIFTY 14 NOV 24500 CALL, Last Traded Price: 12.85, Last Trade Time: 2024-11-12 17:55:49
Instrument: HDFCBANK, Last Traded Price: 1740, Last Trade Time: 2024-11-12 17:55:50
Instrument: BANKNIFTY, Last Traded Price: 51716.5, Last Trade Time: 2024-11-12 17:55:50
Instrument: BANKNIFTY, Last Traded Price: 51715.7, Last Trade Time: 2024-11-12 17:55:50
@Hardik ,
One doubt, the last trade time given in millis is in GMT or IST?
It is in IST only, you just need to unpack it to UTC format.
hey, just saw your response. I am wondering if you would print complete raw data coming from server side. Do they also have day open for different strike price of nifty.
Instrument: NIFTY 14 NOV 24500 CALL, Last Traded Price: 12.85, Last Trade Time: 2024-11-12 17:55:49
Can you please check in Json response that if it has day open price for strike price of nifty. not for the nifty 50 index but for strike price like 23500 CE. Json has open price or not
Hi,
Iâve started exploring dhanAPIâs. Iâve subscribed to Dhan Data APIâs. Able to fetch historical data, option data, etc. Iâve now started experimenting with websockets, live market feed. Saw this message and copy pasted the code in my spring boot app.
So, Iâm getting a 50 feed response from server and below is the logs. Ran the same during market hours.
Request:
{âInstrumentCountâ:1,âInstrumentListâ:[{âSecurityIdâ:â52527â,âExchangeSegmentâ:âNSE_FNOâ}],âRequestCodeâ:15}
Sent subscription request for batch: 1
2024-12-29T14:56:28.568+05:30 INFO 25827 â [dhan-trading] [cTaskExecutor-1] o.s.w.s.c.WebSocketConnectionManager : Successfully connected
Disconnection Code: 808
Connection closed.
Response header byte values: [50, 10, 0, 0, 0, 0, 0, 0]
Never mind: The above code works, I was passing wrong clientId. This has to be the DHAN clientId, instead I was passing the App client which I had registered on DHAN.