diff --git a/.gitignore b/.gitignore index 14570b88..fdea67de 100644 --- a/.gitignore +++ b/.gitignore @@ -56,7 +56,6 @@ local.properties nbproject/private/ build/ nbbuild/ -dist/ nbdist/ nbactions.xml nb-configuration.xml diff --git a/README.md b/README.md index 40a85a33..babcc673 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,519 @@ -# Migrated to New Github Repo https://github.com/angel-one/smartapi-java -For latest updates and bug fixes please refer to the new git repo. +# SmartAPI 2.2.0 Java client +The official Java client for communicating with [SmartAPI Connect API](https://smartapi.angelbroking.com). + +SmartAPI is a set of REST-like APIs that expose many capabilities required to build a complete investment and trading platform. Execute orders in real-time, manage user portfolios, stream live market data (WebSockets), and more, with the simple HTTP API collection. + +## Documentation +- [SmartAPI - HTTP API documentation] (https://smartapi.angelbroking.com/docs) +- [Java library documentation](https://smartapi.angelbroking.com/docs) + +## Usage +- [Download SmartAPI jar file](https://github.com/angel-one/smartapi-java/blob/main/dist/) and include it in your build path. + +- Include com.angelbroking.smartapi into build path from maven. Use version 2.2.0 + +## API usage +```java + // Initialize SamartAPI using Client code, Password, and TOTP. + SmartConnect smartConnect = new SmartConnect(); + + // Provide your API key here + smartConnect.setApiKey(""); + + // Set session expiry callback. + smartConnect.setSessionExpiryHook(new SessionExpiryHook() { + @Override + public void sessionExpired() { + System.out.println("session expired"); + } + }); + + User user = smartConnect.generateSession(, , ); + smartConnect.setAccessToken(user.getAccessToken()); + smartConnect.setUserId(user.getUserId()); + + // token re-generate + + TokenSet tokenSet = smartConnect.renewAccessToken(user.getAccessToken(), + user.getRefreshToken()); + smartConnect.setAccessToken(tokenSet.getAccessToken()); + + /** CONSTANT Details */ + + /* VARIETY */ + /* + * VARIETY_NORMAL: Normal Order (Regular) + * VARIETY_AMO: After Market Order + * VARIETY_STOPLOSS: Stop loss order + * VARIETY_ROBO: ROBO (Bracket) Order + */ + /* TRANSACTION TYPE */ + /* + * TRANSACTION_TYPE_BUY: Buy TRANSACTION_TYPE_SELL: Sell + */ + + /* ORDER TYPE */ + /* + * ORDER_TYPE_MARKET: Market Order(MKT) + * ORDER_TYPE_LIMIT: Limit Order(L) + * ORDER_TYPE_STOPLOSS_LIMIT: Stop Loss Limit Order(SL) + * ORDER_TYPE_STOPLOSS_MARKET: Stop Loss Market Order(SL-M) + */ + + /* PRODUCT TYPE */ + /* + * PRODUCT_DELIVERY: Cash & Carry for equity (CNC) + * PRODUCT_CARRYFORWARD: Normal + * for futures and options (NRML) + * PRODUCT_MARGIN: Margin Delivery + * PRODUCT_INTRADAY: Margin Intraday Squareoff (MIS) + * PRODUCT_BO: Bracket Order + * (Only for ROBO) + */ + + /* DURATION */ + /* + * DURATION_DAY: Valid for a day + * DURATION_IOC: Immediate or Cancel + */ + + /* EXCHANGE */ + /* + * EXCHANGE_BSE: BSE Equity + * EXCHANGE_NSE: NSE Equity + * EXCHANGE_NFO: NSE Future and Options + * EXCHANGE_CDS: NSE Currency + * EXCHANGE_NCDEX: NCDEX Commodity + * EXCHANGE_MCX: MCX Commodity + */ + + /** Place order. */ + public void placeOrder(SmartConnect smartConnect) throws SmartAPIException, IOException { + + OrderParams orderParams = new OrderParams(); + orderParams.variety = "NORMAL"; + orderParams.quantity = 1; + orderParams.symboltoken = "3045"; + orderParams.exchange = Constants.EXCHANGE_NSE; + orderParams.ordertype = Constants.ORDER_TYPE_LIMIT; + orderParams.tradingsymbol = "SBIN-EQ"; + orderParams.producttype = Constants.PRODUCT_INTRADAY; + orderParams.duration = Constants.VALIDITY_DAY; + orderParams.transactiontype = Constants.TRANSACTION_TYPE_BUY; + orderParams.price = 122.2; + orderParams.squareoff = "0"; + orderParams.stoploss = "0"; + + Order order = smartConnect.placeOrder(orderParams, Constants.VARIETY_REGULAR); + } + + /** Modify order. */ + public void modifyOrder(SmartConnect smartConnect) throws SmartAPIException, IOException { + // Modify order request will return the order model which will contain order_id. + + OrderParams orderParams = new OrderParams(); + orderParams.quantity = 1; + orderParams.ordertype = Constants.ORDER_TYPE_LIMIT; + orderParams.tradingsymbol = "ASHOKLEY"; + orderParams.symboltoken = "3045"; + orderParams.producttype = Constants.PRODUCT_DELIVERY; + orderParams.exchange = Constants.EXCHANGE_NSE; + orderParams.duration = Constants.VALIDITY_DAY; + orderParams.price = 122.2; + + String orderId = "201216000755110"; + Order order = smartConnect.modifyOrder(orderId, orderParams, Constants.VARIETY_REGULAR); + } + + /** Cancel order */ + public void cancelOrder(SmartConnect smartConnect) throws SmartAPIException, IOException { + // Cancel order will return the order model which will have orderId. + String orderId = "201216000755110"; + Order order = smartConnect.cancelOrder(orderId, Constants.VARIETY_REGULAR); + } + + /** Get order details */ + public void getOrder(SmartConnect smartConnect) throws SmartAPIException, IOException { + List orders = smartConnect.getOrderHistory(smartConnect.getUserId()); + for (int i = 0; i < orders.size(); i++) { + System.out.println(orders.get(i).orderId + " " + orders.get(i).status); + } + } + + /** + * Get the last price for multiple instruments at once. Users can either pass + * exchange with tradingsymbol or instrument token only. For example {NSE:NIFTY + * 50, BSE:SENSEX} or {256265, 265} + */ + public void getLTP(SmartConnect smartConnect) throws SmartAPIException, IOException { + String exchange = "NSE"; + String tradingSymbol = "SBIN-EQ"; + String symboltoken = "3045"; + JSONObject ltpData = smartConnect.getLTP(exchange, tradingSymbol, symboltoken); + } + + /** Get tradebook */ + public void getTrades(SmartConnect smartConnect) throws SmartAPIException, IOException { + // Returns tradebook. + List trades = smartConnect.getTrades(); + for (int i = 0; i < trades.size(); i++) { + System.out.println(trades.get(i).tradingSymbol + " " + trades.size()); + } + } + + /** Get Margin in trading account*/ + public void getRMS(SmartConnect smartConnect) throws SmartAPIException, IOException { + // Returns RMS. + JSONObject response = smartConnect.getRMS(); + } + + /** Get Holdings */ + public void getHolding(SmartConnect smartConnect) throws SmartAPIException, IOException { + // Returns Holding. + JSONObject response = smartConnect.getHolding(); + } + + /** Get All Holdings */ + public void getAllHolding(SmartConnect smartConnect) throws SmartAPIException, IOException { + // Returns Holdings. + JSONObject response = smartConnect.getAllHolding(); + } + + /** Get Position */ + public void getPosition(SmartConnect smartConnect) throws SmartAPIException, IOException { + // Returns Position. + JSONObject response = smartConnect.getPosition(); + } + + /** convert Position */ + public void convertPosition(SmartConnect smartConnect) throws SmartAPIException, IOException { + + JSONObject requestObejct = new JSONObject(); + requestObejct.put("exchange", "NSE"); + requestObejct.put("oldproducttype", "DELIVERY"); + requestObejct.put("newproducttype", "MARGIN"); + requestObejct.put("tradingsymbol", "SBIN-EQ"); + requestObejct.put("transactiontype", "BUY"); + requestObejct.put("quantity", 1); + requestObejct.put("type", "DAY"); + + JSONObject response = smartConnect.convertPosition(requestObejct); + } + + /** Create Gtt Rule*/ + public void createRule(SmartConnect smartConnect)throws SmartAPIException,IOException{ + GttParams gttParams= new GttParams(); + + gttParams.tradingsymbol="SBIN-EQ"; + gttParams.symboltoken="3045"; + gttParams.exchange="NSE"; + gttParams.producttype="MARGIN"; + gttParams.transactiontype="BUY"; + gttParams.price= 100000.01; + gttParams.qty=10; + gttParams.disclosedqty=10; + gttParams.triggerprice=20000.1; + gttParams.timeperiod=300; + + Gtt gtt = smartConnect.gttCreateRule(gttParams); + } + + + /** Modify Gtt Rule */ + public void modifyRule(SmartConnect smartConnect)throws SmartAPIException,IOException{ + GttParams gttParams= new GttParams(); + + gttParams.tradingsymbol="SBIN-EQ"; + gttParams.symboltoken="3045"; + gttParams.exchange="NSE"; + gttParams.producttype="MARGIN"; + gttParams.transactiontype="BUY"; + gttParams.price= 100000.1; + gttParams.qty=10; + gttParams.disclosedqty=10; + gttParams.triggerprice=20000.1; + gttParams.timeperiod=300; + + Integer id= 1000051; + + Gtt gtt = smartConnect.gttModifyRule(id,gttParams); + } + + /** Cancel Gtt Rule */ + public void cancelRule(SmartConnect smartConnect)throws SmartAPIException, IOException{ + Integer id=1000051; + String symboltoken="3045"; + String exchange="NSE"; + + Gtt gtt = smartConnect.gttCancelRule(id,symboltoken,exchange); + } + + /** Gtt Rule Details */ + public void ruleDetails(SmartConnect smartConnect)throws SmartAPIException, IOException{ + Integer id=1000051; + + JSONObject gtt = smartConnect.gttRuleDetails(id); + } + + /** Gtt Rule Lists */ + public void ruleList(SmartConnect smartConnect)throws SmartAPIException, IOException{ + + List status=new ArrayList(){{ + add("NEW"); + add("CANCELLED"); + add("ACTIVE"); + add("SENTTOEXCHANGE"); + add("FORALL"); + }}; + Integer page=1; + Integer count=10; + + JSONArray gtt = smartConnect.gttRuleList(status,page,count); + } + + /** Historic Data */ + public void getCandleData(SmartConnect smartConnect) throws SmartAPIException, IOException { + + JSONObject requestObejct = new JSONObject(); + requestObejct.put("exchange", "NSE"); + requestObejct.put("symboltoken", "3045"); + requestObejct.put("interval", "ONE_MINUTE"); + requestObejct.put("fromdate", "2021-03-08 09:00"); + requestObejct.put("todate", "2021-03-09 09:20"); + + String response = smartConnect.candleData(requestObejct); + } + + + /** Search Scrip Data */ + public void getSearchScrip(SmartConnect smartConnect) throws SmartAPIException{ + JSONObject payload = new JSONObject(); + payload.put("exchange", "MCX"); + payload.put("searchscrip", "Crude"); + String response = smartConnect.getSearchScrip(payload); + } + + /** Logout user. */ + + /** Market Data FULL*/ + public void getMarketData(SmartConnect smartConnect) { + + JSONObject payload = new JSONObject(); + payload.put("mode", "FULL"); + JSONObject exchangeTokens = new JSONObject(); + JSONArray nseTokens = new JSONArray(); + nseTokens.put("3045"); + exchangeTokens.put("NSE", nseTokens); + payload.put("exchangeTokens", exchangeTokens); + JSONObject response = smartConnect.marketData(payload); + + } + + /** Market Data OHLC*/ + public void getMarketData(SmartConnect smartConnect) { + + JSONObject payload = new JSONObject(); + payload.put("mode", "OHLC"); + JSONObject exchangeTokens = new JSONObject(); + JSONArray nseTokens = new JSONArray(); + nseTokens.put("3045"); + exchangeTokens.put("NSE", nseTokens); + payload.put("exchangeTokens", exchangeTokens); + JSONObject response = smartConnect.marketData(payload); + + } + + /** Market Data LTP*/ + public void getMarketData(SmartConnect smartConnect) { + + JSONObject payload = new JSONObject(); + payload.put("mode", "LTP"); + JSONObject exchangeTokens = new JSONObject(); + JSONArray nseTokens = new JSONArray(); + nseTokens.put("3045"); + exchangeTokens.put("NSE", nseTokens); + payload.put("exchangeTokens", exchangeTokens); + JSONObject response = smartConnect.marketData(payload); + + } + + /** Logout user. */ + public void logout(SmartConnect smartConnect) throws SmartAPIException, IOException { + /** Logout user and kill the session. */ + JSONObject jsonObject = smartConnect.logout(); + } + + +/** Margin data. */ +public void getMarginDetails(SmartConnect smartConnect) throws SmartAPIException, IOException { + List marginParamsList = new ArrayList<>(); + MarginParams marginParams = new MarginParams(); + marginParams.quantity = 1; + marginParams.token = "12740"; + marginParams.exchange = Constants.EXCHANGE_NSE; + marginParams.productType = Constants.PRODUCT_DELIVERY; + marginParams.price = 0.0; + marginParams.tradeType = Constants.TRADETYPE_BUY; + + marginParamsList.add(marginParams); + JSONObject jsonObject = smartConnect.getMarginDetails(marginParamsList); + System.out.println(jsonObject); + } + + /** Get Individual Order */ + public void getIndividualOrder(SmartConnect smartConnect, String orderId) throws SmartAPIException, IOException { + + JSONObject jsonObject = smartConnect.getIndividualOrderDetails(orderId); + } +} + +``` + +## WebSocket live streaming data + +```java + + /* Smart Stream */ + String clientCode = "client_code"; + User user = smartConnect.generateSession(clientCode, "", ""); + String feedToken = user.getFeedToken(); + SmartStreamListener smartStreamListener = new SmartStreamListener() { + @Override + public void onLTPArrival(LTP ltp) { + System.out.println("ltp value==========>" + ltp.getExchangeType()); + } + + @Override + public void onQuoteArrival(Quote quote) { + + } + + @Override + public void onSnapQuoteArrival(SnapQuote snapQuote) { + + } + + @Override + public void onDepthArrival(Depth depth) { + + } + + @Override + public void onConnected() { + System.out.println("connected successfully"); + } + + @Override + public void onDisconnected() { + + } + + @Override + public void onError(SmartStreamError smartStreamError) { + + } + + @Override + public void onPong() { + + } + + @Override + public SmartStreamError onErrorCustom() { + return null; + } + }; + +SmartStreamTicker smartStreamTicker = new SmartStreamTicker(clientCode,feedToken,smartStreamListener); +smartStreamTicker.connect(); +Boolean connection = smartStreamTicker.isConnectionOpen(); + +Set tokenSet = new HashSet<>(); +tokenSet.add(new TokenID(ExchangeType.NSE_CM, "26000")); // NIFTY +tokenSet.add(new TokenID(ExchangeType.NSE_CM, "26009")); // NIFTY BANK +tokenSet.add(new TokenID(ExchangeType.BSE_CM, "19000")); + +smartStreamTicker.subscribe(SmartStreamSubsMode.LTP,tokenSet); +smartStreamTicker.disconnect(); +``` +For more details, take a look at Examples.java in the sample directory. + + +## Order Websocket Data + +```java + + /* Order Websocket */ + String userClientId = ""; + User userGenerateSession = smartConnect.generateSession("", "", ""); + smartConnect.setAccessToken(userGenerateSession.getAccessToken()); + smartConnect.setUserId(userGenerateSession.getUserId()); + String accessToken = userGenerateSession.getAccessToken(); + + examples.orderUpdateUsage(accessToken); + + /** + * Order update websocket + * + * To retrieve order update websocket data + * @param accessToken + */ + public void orderUpdateUsage(String accessToken){ + OrderUpdateWebsocket orderUpdateWebsocket = new OrderUpdateWebsocket(accessToken, new OrderUpdateListner() { + /** + * Check if the websocket is connected or not + */ + @Override + public void onConnected() { + + log.info("order update websocket connected"); + + } + + /** + * Handle the onDisconnected event + */ + @Override + public void onDisconnected() { + + log.info("order update websocket disconnected"); + + } + + /** + * Handle the onError event + * @param error + */ + @Override + public void onError(SmartStreamError error) { + + log.info("on error event"); + + } + + /** + * Handle the onPong event + */ + @Override + public void onPong() { + + log.info("or pong event"); + + } + + /** + * Handle the onOrderUpdate event + * @param data + */ + @Override + public void onOrderUpdate(String data) { + + log.info("order update data {} ",data); + + }}); + + } + +``` +For more details, take a look at Examples.java in the sample directory. diff --git a/dist/smartapi-java-2.0.0.jar b/dist/smartapi-java-2.0.0.jar new file mode 100644 index 00000000..51339e84 Binary files /dev/null and b/dist/smartapi-java-2.0.0.jar differ diff --git a/dist/smartapi-java-2.1.0.jar b/dist/smartapi-java-2.1.0.jar new file mode 100644 index 00000000..7b109d8e Binary files /dev/null and b/dist/smartapi-java-2.1.0.jar differ diff --git a/dist/smartapi-java-2.2.0.jar b/dist/smartapi-java-2.2.0.jar new file mode 100644 index 00000000..f045d95a Binary files /dev/null and b/dist/smartapi-java-2.2.0.jar differ diff --git a/dist/smartapi-java-2.2.1.jar b/dist/smartapi-java-2.2.1.jar new file mode 100644 index 00000000..4c0a9495 Binary files /dev/null and b/dist/smartapi-java-2.2.1.jar differ diff --git a/dist/smartapi-java-2.2.2.jar b/dist/smartapi-java-2.2.2.jar new file mode 100644 index 00000000..0eddbc0a Binary files /dev/null and b/dist/smartapi-java-2.2.2.jar differ diff --git a/dist/smartapi-java-2.2.3.jar b/dist/smartapi-java-2.2.3.jar new file mode 100644 index 00000000..95ce7dba Binary files /dev/null and b/dist/smartapi-java-2.2.3.jar differ diff --git a/dist/smartapi-java-2.2.4.jar b/dist/smartapi-java-2.2.4.jar new file mode 100644 index 00000000..88a8afd6 Binary files /dev/null and b/dist/smartapi-java-2.2.4.jar differ diff --git a/dist/smartapi-java-2.2.5.jar b/dist/smartapi-java-2.2.5.jar new file mode 100644 index 00000000..d18852bb Binary files /dev/null and b/dist/smartapi-java-2.2.5.jar differ diff --git a/dist/smartapi-java-2.2.6.jar b/dist/smartapi-java-2.2.6.jar new file mode 100644 index 00000000..d18e1ebd Binary files /dev/null and b/dist/smartapi-java-2.2.6.jar differ diff --git a/doc/com/angelbroking/smartapi/sample/Test.html b/doc/com/angelbroking/smartapi/sample/Test.html index deaaccd3..5b154305 100644 --- a/doc/com/angelbroking/smartapi/sample/Test.html +++ b/doc/com/angelbroking/smartapi/sample/Test.html @@ -100,7 +100,7 @@

Class Test

  • java.lang.Object
    • -
    • com.angelbroking.smartapi.sample.Test
    • +
    • com.angelbroking.smartapi.sample.APITest
  • diff --git a/doc/com/angelbroking/smartapi/sample/class-use/Test.html b/doc/com/angelbroking/smartapi/sample/class-use/Test.html index 1ca84cdc..d77c3aab 100644 --- a/doc/com/angelbroking/smartapi/sample/class-use/Test.html +++ b/doc/com/angelbroking/smartapi/sample/class-use/Test.html @@ -3,7 +3,7 @@ -Uses of Class com.angelbroking.smartapi.sample.Test +Uses of Class com.angelbroking.smartapi.sample.APITest @@ -70,9 +70,9 @@
    -

    Uses of Class
    com.angelbroking.smartapi.sample.Test

    +

    Uses of Class
    com.angelbroking.smartapi.sample.APITest

    -
    No usage of com.angelbroking.smartapi.sample.Test
    +
    No usage of com.angelbroking.smartapi.sample.APITest
    diff --git a/error.log b/error.log new file mode 100644 index 00000000..e69de29b diff --git a/pom.xml b/pom.xml index e19bcb34..ebc8e8c8 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ com.angelbroking.smartapi smartapi-java - 1.0.0 + 2.2.6 jar smartapi-java @@ -20,71 +20,214 @@ + 1.8 + 3.8.1 + 3.5.1 UTF-8 + 5.8.1 + 5.5.0 + 3.24.2 + 1.16.0 + 2.4.0 + 2.14 + 20230618 + 4.11.0 + 3.6.0 + 4.11.0 + 1.9.10 + 2.10.1 + 2.0.9 + 1.4.11 + 8.16.0 + 1.18.30 + 4.12 + 5.5.0 + 4.11.0 + 1.5.0 + 3.0.1 + 1.7.32 + 1.2.6 + + + + org.projectlombok + lombok + ${lombok.version} + + + com.spotify + docker-client + ${docker-client.version} + + + commons-codec + commons-codec + ${commons-codec.version} + + + net.sf.supercsv + super-csv + ${super-csv.version} + + + com.neovisionaries + nv-websocket-client + ${nv-websocket-client.version} + + + + org.json + json + ${json.version} + + + com.squareup.okhttp3 + okhttp + ${okhttp.version} + + + com.squareup.okio + okio + ${okio.version} + + + com.squareup.okhttp3 + logging-interceptor + ${logging-interceptor.version} + + + org.jetbrains.kotlin + kotlin-stdlib + ${kotlin-stdlib.version} + + + com.google.code.gson + gson + ${gson.version} + + + + + org.mockito + mockito-core + ${mockito.version} + test + + + + + org.assertj + assertj-core + ${assertj.version} + test + + + + + org.slf4j + slf4j-api + ${slf4j-api.version} + + + + + ch.qos.logback + logback-classic + ${logback-classic.version} + + + + junit + junit + ${junit.version} + test + + + + org.mockito + mockito-junit-jupiter + ${mockito-junit-jupiter.version} + test + + + com.squareup.okhttp3 + mockwebserver + ${okhttp.mockwebserver.version} + test + + + com.warrenstrange + googleauth + ${google-auth.version} + + + com.github.tomakehurst + wiremock + ${wiremock.version} + + + org.slf4j + slf4j-api + ${slf4j-api.version} + + + ch.qos.logback + logback-classic + ${logback-classic.version} + + + - - + + org.apache.maven.plugins maven-compiler-plugin + ${maven-compiler-plugin-version} - 1.8 - 1.8 + ${java-version} + ${java-version} + + + org.apache.maven.plugins + maven-shade-plugin + ${maven-shade-plugin-version} + + + + shade + + + true + + + com.angelbroking.smartapi.Main + + true + + + + + + + *:* + + META-INF/*.SF + META-INF/*.DSA + META-INF/*.RSA + + + + + + + + + - - - commons-codec - commons-codec - 1.11 - - - net.sf.supercsv - super-csv - 2.4.0 - - - - com.neovisionaries - nv-websocket-client - 2.10 - - - - org.json - json - 20171018 - - - com.squareup.okhttp3 - okhttp - 4.4.0 - - - com.squareup.okio - okio - 2.4.3 - - - com.squareup.okhttp3 - logging-interceptor - 4.4.0 - - - org.jetbrains.kotlin - kotlin-stdlib - 1.3.70 - - - com.google.code.gson - gson - 2.6.2 - - - diff --git a/src/main/java/com/angelbroking/smartapi/Routes.java b/src/main/java/com/angelbroking/smartapi/Routes.java index 59c4a080..52ee185f 100644 --- a/src/main/java/com/angelbroking/smartapi/Routes.java +++ b/src/main/java/com/angelbroking/smartapi/Routes.java @@ -13,10 +13,12 @@ public class Routes { public Map routes; - private static String _rootUrl = "https://apiconnect.angelbroking.com"; - private static String _loginUrl = "https://apiconnect.angelbroking.com/rest/auth/angelbroking/user/v1/loginByPassword"; + private static String _rootUrl = "https://apiconnect.angelone.in"; + private static String _loginUrl = _rootUrl+"/rest/auth/angelbroking/user/v1/loginByPassword"; private static String _wsuri = "wss://wsfeeds.angelbroking.com/NestHtml5Mobile/socket/stream"; + private static String _smartStreamWSURI = "wss://smartapisocket.angelone.in/smart-stream"; private static String _swsuri = "wss://smartapisocket.angelbroking.com/websocket"; + private static String _orderUpdateUri = "wss://tns.angelone.in/smart-order-update"; // Initialize all routes, @SuppressWarnings("serial") @@ -33,6 +35,7 @@ public Routes() { put("api.order.book", "/rest/secure/angelbroking/order/v1/getOrderBook"); put("api.order.trade.book", "/rest/secure/angelbroking/order/v1/getTradeBook"); put("api.order.rms.data", "/rest/secure/angelbroking/user/v1/getRMS"); + put("api.order.rms.AllHolding", "/rest/secure/angelbroking/portfolio/v1/getAllHolding"); put("api.order.rms.holding", "/rest/secure/angelbroking/portfolio/v1/getHolding"); put("api.order.rms.position", "/rest/secure/angelbroking/order/v1/getPosition"); put("api.order.rms.position.convert", "/rest/secure/angelbroking/order/v1/convertPosition"); @@ -43,7 +46,21 @@ public Routes() { put("api.gtt.details", "/rest/secure/angelbroking/gtt/v1/ruleDetails"); put("api.gtt.list", "/rest/secure/angelbroking/gtt/v1/ruleList"); put("api.candle.data", "/rest/secure/angelbroking/historical/v1/getCandleData"); - + put("api.oi.data", "/rest/secure/angelbroking/historical/v1/getOIData"); + put("api.search.script.data", "/rest/secure/angelbroking/order/v1/searchScrip"); + put("api.market.data", "/rest/secure/angelbroking/market/v1/quote"); + put("api.margin.batch", "/rest/secure/angelbroking/margin/v1/batch"); + put("api.individual.order", "/rest/secure/angelbroking/order/v1/details/"); + put("api.estimateCharges", "/rest/secure/angelbroking/brokerage/v1/estimateCharges"); + put("api.verifyDis", "/rest/secure/angelbroking/edis/v1/verifyDis"); + put("api.generateTPIN", "/rest/secure/angelbroking/edis/v1/generateTPIN"); + put("api.getTranStatus", "/rest/secure/angelbroking/edis/v1/getTranStatus"); + put("api.optionGreek", "/rest/secure/angelbroking/marketData/v1/optionGreek"); + put("api.gainersLosers", "/rest/secure/angelbroking/marketData/v1/gainersLosers"); + put("api.putCallRatio", "/rest/secure/angelbroking/marketData/v1/putCallRatio"); + put("api.nseIntraday", "/rest/secure/angelbroking/marketData/v1/nseIntraday"); + put("api.bseIntraday", "/rest/secure/angelbroking/marketData/v1/bseIntraday"); + put("api.oIBuildup", "/rest/secure/angelbroking/marketData/v1/OIBuildup"); } }; } @@ -63,4 +80,12 @@ public String getWsuri() { public String getSWsuri() { return _swsuri; } + + public String getSmartStreamWSURI() { + return _smartStreamWSURI; + } + + public String getOrderUpdateUri() { + return _orderUpdateUri; + } } diff --git a/src/main/java/com/angelbroking/smartapi/SmartConnect.java b/src/main/java/com/angelbroking/smartapi/SmartConnect.java index d1b3003b..6bc9f4fd 100644 --- a/src/main/java/com/angelbroking/smartapi/SmartConnect.java +++ b/src/main/java/com/angelbroking/smartapi/SmartConnect.java @@ -1,24 +1,30 @@ package com.angelbroking.smartapi; -import java.io.IOException; -import java.net.Proxy; -import java.util.List; - +import com.angelbroking.smartapi.http.SessionExpiryHook; +import com.angelbroking.smartapi.http.SmartAPIRequestHandler; +import com.angelbroking.smartapi.http.exceptions.SmartAPIException; +import com.angelbroking.smartapi.models.*; +import lombok.extern.slf4j.Slf4j; import org.apache.commons.codec.digest.DigestUtils; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; -import com.angelbroking.smartapi.http.SessionExpiryHook; -import com.angelbroking.smartapi.http.SmartAPIRequestHandler; -import com.angelbroking.smartapi.http.exceptions.SmartAPIException; -import com.angelbroking.smartapi.models.Gtt; -import com.angelbroking.smartapi.models.GttParams; -import com.angelbroking.smartapi.models.Order; -import com.angelbroking.smartapi.models.OrderParams; -import com.angelbroking.smartapi.models.TokenSet; -import com.angelbroking.smartapi.models.User; + +import java.io.IOException; +import java.net.Proxy; +import java.util.List; +import javax.net.ssl.HttpsURLConnection; + +import static com.angelbroking.smartapi.utils.Constants.IO_EXCEPTION_ERROR_MSG; +import static com.angelbroking.smartapi.utils.Constants.IO_EXCEPTION_OCCURRED; +import static com.angelbroking.smartapi.utils.Constants.JSON_EXCEPTION_ERROR_MSG; +import static com.angelbroking.smartapi.utils.Constants.JSON_EXCEPTION_OCCURRED; +import static com.angelbroking.smartapi.utils.Constants.SMART_API_EXCEPTION_ERROR_MSG; +import static com.angelbroking.smartapi.utils.Constants.SMART_API_EXCEPTION_OCCURRED; + +@Slf4j public class SmartConnect { public static SessionExpiryHook sessionExpiryHook = null; public static boolean ENABLE_LOGGING = false; @@ -28,10 +34,11 @@ public class SmartConnect { private String refreshToken; private Routes routes = new Routes(); private String userId; - private SmartAPIRequestHandler smartAPIRequestHandler; + private SmartAPIRequestHandler smartAPIRequestHandler = new SmartAPIRequestHandler(proxy); public SmartConnect() { - + //setting up TLS min and max version + System.setProperty("https.protocols","TLSv1.2,TLSv1.3"); } public SmartConnect(String apiKey) { @@ -50,7 +57,7 @@ public void setApiKey(String apiKey) { /** * Registers callback for session error. - * + * * @param hook can be set to get callback when session is expired. */ public void setSessionExpiryHook(SessionExpiryHook hook) { @@ -59,7 +66,7 @@ public void setSessionExpiryHook(SessionExpiryHook hook) { /** * Returns apiKey of the App. - * + * * @return String apiKey is returned. * @throws NullPointerException if _apiKey is not found. */ @@ -72,7 +79,7 @@ public String getApiKey() throws NullPointerException { /** * Returns accessToken. - * + * * @return String access_token is returned. * @throws NullPointerException if accessToken is null. */ @@ -85,7 +92,7 @@ public String getAccessToken() throws NullPointerException { /** * Returns userId. - * + * * @return String userId is returned. * @throws NullPointerException if userId is null. */ @@ -99,7 +106,7 @@ public String getUserId() throws NullPointerException { /** * Set userId. - * + * * @param id is user_id. */ public void setUserId(String id) { @@ -108,7 +115,7 @@ public void setUserId(String id) { /** * Returns publicToken. - * + * * @throws NullPointerException if publicToken is null. * @return String public token is returned. */ @@ -122,7 +129,7 @@ public String getPublicToken() throws NullPointerException { /** * Set the accessToken received after a successful authentication. - * + * * @param accessToken is the access token received after sending request token * and api secret. */ @@ -132,7 +139,7 @@ public void setAccessToken(String accessToken) { /** * Set publicToken. - * + * * @param publicToken is the public token received after sending request token * and api secret. */ @@ -142,7 +149,7 @@ public void setRefreshToken(String refreshToken) { /** * Retrieves login url - * + * * @return String loginUrl is returned. */ public String getLoginURL() throws NullPointerException { @@ -153,13 +160,13 @@ public String getLoginURL() throws NullPointerException { /** * Do the token exchange with the `request_token` obtained after the login flow, * and retrieve the `access_token` required for all subsequent requests. - * + * * @param requestToken received from login process. * @param apiSecret which is unique for each aap. * @return User is the user model which contains user and session details. - * + * */ - public User generateSession(String clientCode, String password) { + public User generateSession(String clientCode, String password, String totp) { try { smartAPIRequestHandler = new SmartAPIRequestHandler(proxy); @@ -167,10 +174,11 @@ public User generateSession(String clientCode, String password) { JSONObject params = new JSONObject(); params.put("clientcode", clientCode); params.put("password", password); + params.put("totp", totp); JSONObject loginResultObject = smartAPIRequestHandler.postRequest(this.apiKey, routes.getLoginUrl(), params); - System.out.print(loginResultObject); + log.info("login result: {}",loginResultObject); String jwtToken = loginResultObject.getJSONObject("data").getString("jwtToken"); String refreshToken = loginResultObject.getJSONObject("data").getString("refreshToken"); String feedToken = loginResultObject.getJSONObject("data").getString("feedToken"); @@ -182,7 +190,7 @@ public User generateSession(String clientCode, String password) { return user; } catch (Exception | SmartAPIException e) { - System.out.println(e.getMessage()); + log.error(e.getMessage()); return null; } @@ -190,11 +198,11 @@ public User generateSession(String clientCode, String password) { /** * Get a new access token using refresh token. - * + * * @param refreshToken is the refresh token obtained after generateSession. * @param apiSecret is unique for each app. * @return TokenSet contains user id, refresh token, api secret. - * + * */ public TokenSet renewAccessToken(String accessToken, String refreshToken) { try { @@ -217,14 +225,14 @@ public TokenSet renewAccessToken(String accessToken, String refreshToken) { return tokenSet; } catch (Exception | SmartAPIException e) { - System.out.println(e.getMessage()); + log.error(e.getMessage()); return null; } } /** * Hex encodes sha256 output for android support. - * + * * @return Hex encoded String. * @param str is the String that has to be encrypted. */ @@ -238,9 +246,9 @@ public String sha256Hex(String str) { /** * Get the profile details of the use. - * + * * @return Profile is a POJO which contains profile related data. - * + * */ public User getProfile() { try { @@ -248,19 +256,19 @@ public User getProfile() { User user = new User().parseResponse(smartAPIRequestHandler.getRequest(this.apiKey, url, accessToken)); return user; } catch (Exception | SmartAPIException e) { - System.out.println(e.getMessage()); + log.error(e.getMessage()); return null; } } /** * Places an order. - * + * * @param orderParams is Order params. * @param variety variety="regular". Order variety can be bo, co, amo, * regular. * @return Order contains only orderId. - * + * */ public Order placeOrder(OrderParams orderParams, String variety) { @@ -301,10 +309,11 @@ public Order placeOrder(OrderParams orderParams, String variety) { JSONObject jsonObject = smartAPIRequestHandler.postRequest(this.apiKey, url, params, accessToken); Order order = new Order(); order.orderId = jsonObject.getJSONObject("data").getString("orderid"); - System.out.println(order); + order.uniqueOrderId = jsonObject.getJSONObject("data").getString("uniqueorderid"); + log.info("order : {}",order); return order; } catch (Exception | SmartAPIException e) { - System.out.println(e.getMessage()); + log.error(e.getMessage()); return null; } } @@ -317,7 +326,7 @@ public Order placeOrder(OrderParams orderParams, String variety) { * regular. * @param orderId order id of the order being modified. * @return Order object contains only orderId. - * + * */ public Order modifyOrder(String orderId, OrderParams orderParams, String variety) { try { @@ -350,19 +359,19 @@ public Order modifyOrder(String orderId, OrderParams orderParams, String variety order.orderId = jsonObject.getJSONObject("data").getString("orderid"); return order; } catch (Exception | SmartAPIException e) { - System.out.println(e.getMessage()); + log.error(e.getMessage()); return null; } } /** * Cancels an order. - * + * * @param orderId order id of the order to be cancelled. * @param variety [variety="regular"]. Order variety can be bo, co, amo, * regular. * @return Order object contains only orderId. - * + * */ public Order cancelOrder(String orderId, String variety) { try { @@ -376,28 +385,28 @@ public Order cancelOrder(String orderId, String variety) { order.orderId = jsonObject.getJSONObject("data").getString("orderid"); return order; } catch (Exception | SmartAPIException e) { - System.out.println(e.getMessage()); + log.error(e.getMessage()); return null; } } /** * Returns list of different stages an order has gone through. - * + * * @return List of multiple stages an order has gone through in the system. * @throws SmartAPIException is thrown for all Smart API trade related errors. * @param orderId is the order id which is obtained from orderbook. - * + * */ @SuppressWarnings({}) public JSONObject getOrderHistory(String clientId) { try { String url = routes.get("api.order.book"); JSONObject response = smartAPIRequestHandler.getRequest(this.apiKey, url, accessToken); - System.out.println(response); + log.info("Order history : {}",response); return response; } catch (Exception | SmartAPIException e) { - System.out.println("Exception#: " + e.getMessage()); + log.error("Exception#: {}" , e.getMessage()); e.printStackTrace(); return null; } @@ -407,9 +416,9 @@ public JSONObject getOrderHistory(String clientId) { * Retrieves last price. User can either pass exchange with tradingsymbol or * instrument token only. For example {NSE:NIFTY 50, BSE:SENSEX} or {256265, * 265}. - * + * * @return Map of String and LTPQuote. - * + * */ public JSONObject getLTP(String exchange, String tradingSymbol, String symboltoken) { try { @@ -423,14 +432,14 @@ public JSONObject getLTP(String exchange, String tradingSymbol, String symboltok return response.getJSONObject("data"); } catch (Exception | SmartAPIException e) { - System.out.println(e.getMessage()); + log.error(e.getMessage()); return null; } } /** * Retrieves list of trades executed. - * + * * @return List of trades. */ public JSONObject getTrades() { @@ -439,14 +448,14 @@ public JSONObject getTrades() { JSONObject response = smartAPIRequestHandler.getRequest(this.apiKey, url, accessToken); return response; } catch (Exception | SmartAPIException e) { - System.out.println(e.getMessage()); + log.error(e.getMessage()); return null; } } /** * Retrieves RMS. - * + * * @return Object of RMS. * @throws SmartAPIException is thrown for all Smart API trade related errors. * @throws JSONException is thrown when there is exception while parsing @@ -459,16 +468,16 @@ public JSONObject getRMS() { JSONObject response = smartAPIRequestHandler.getRequest(this.apiKey, url, accessToken); return response.getJSONObject("data"); } catch (Exception | SmartAPIException e) { - System.out.println(e.getMessage()); + log.error(e.getMessage()); return null; } } /** * Retrieves Holding. - * + * * @return Object of Holding. - * + * */ public JSONObject getHolding() { try { @@ -476,16 +485,39 @@ public JSONObject getHolding() { JSONObject response = smartAPIRequestHandler.getRequest(this.apiKey, url, accessToken); return response; } catch (Exception | SmartAPIException e) { - System.out.println(e.getMessage()); + log.error(e.getMessage()); return null; } } + + /** + * Retrieves All Holdings. + * + * @return Object of Holding. + * + */ + public JSONObject getAllHolding() throws SmartAPIException, IOException { + try { + String url = routes.get("api.order.rms.AllHolding"); + return smartAPIRequestHandler.getRequest(this.apiKey, url, accessToken); + } catch (SmartAPIException ex) { + log.error("{} while getting all holdings {}", SMART_API_EXCEPTION_OCCURRED, ex.toString()); + throw new SmartAPIException(String.format("%s in getting all holdings %s", SMART_API_EXCEPTION_ERROR_MSG, ex)); + } catch (IOException ex) { + log.error("{} while getting all holdings {}", IO_EXCEPTION_OCCURRED, ex.getMessage()); + throw new IOException(String.format("%s in getting all holdings %s", IO_EXCEPTION_ERROR_MSG, ex.getMessage())); + } catch (JSONException ex) { + log.error("{} while getting all holdings {}", JSON_EXCEPTION_OCCURRED, ex.getMessage()); + throw new JSONException(String.format("%s in getting all holdings %s", JSON_EXCEPTION_ERROR_MSG, ex.getMessage())); + } + } + /** * Retrieves position. - * + * * @return Object of position. - * + * */ public JSONObject getPosition() { try { @@ -493,14 +525,14 @@ public JSONObject getPosition() { JSONObject response = smartAPIRequestHandler.getRequest(this.apiKey, url, accessToken); return response; } catch (Exception | SmartAPIException e) { - System.out.println(e.getMessage()); + log.error(e.getMessage()); return null; } } /** * Retrieves conversion. - * + * * @return Object of conversion. * @throws SmartAPIException is thrown for all Smart API trade related errors. * @throws JSONException is thrown when there is exception while parsing @@ -513,17 +545,17 @@ public JSONObject convertPosition(JSONObject params) { JSONObject response = smartAPIRequestHandler.postRequest(this.apiKey, url, params, accessToken); return response; } catch (Exception | SmartAPIException e) { - System.out.println(e.getMessage()); + log.error(e.getMessage()); return null; } } /** * Create a Gtt Rule. - * + * * @param gttParams is gtt Params. * @return Gtt contains only orderId. - * + * */ public Gtt gttCreateRule(GttParams gttParams) { @@ -556,10 +588,10 @@ public Gtt gttCreateRule(GttParams gttParams) { JSONObject jsonObject = smartAPIRequestHandler.postRequest(this.apiKey, url, params, accessToken); Gtt gtt = new Gtt(); gtt.id = jsonObject.getJSONObject("data").getInt("id"); - System.out.println(gtt); + log.info("gtt : {}",gtt); return gtt; } catch (Exception | SmartAPIException e) { - System.out.println(e.getMessage()); + log.error(e.getMessage()); return null; } @@ -567,10 +599,10 @@ public Gtt gttCreateRule(GttParams gttParams) { /** * Modify a Gtt Rule. - * + * * @param gttParams is gtt Params. * @return Gtt contains only orderId. - * + * */ public Gtt gttModifyRule(Integer id, GttParams gttParams) { @@ -599,10 +631,10 @@ public Gtt gttModifyRule(Integer id, GttParams gttParams) { JSONObject jsonObject = smartAPIRequestHandler.postRequest(this.apiKey, url, params, accessToken); Gtt gtt = new Gtt(); gtt.id = jsonObject.getJSONObject("data").getInt("id"); - System.out.println(gtt); + log.info("gtt : {}",gtt); return gtt; } catch (Exception | SmartAPIException e) { - System.out.println(e.getMessage()); + log.error(e.getMessage()); return null; } @@ -610,7 +642,7 @@ public Gtt gttModifyRule(Integer id, GttParams gttParams) { /** * Cancel a Gtt Rule. - * + * * @param gttParams is gtt Params. * @return Gtt contains only orderId. */ @@ -626,17 +658,17 @@ public Gtt gttCancelRule(Integer id, String symboltoken, String exchange) { JSONObject jsonObject = smartAPIRequestHandler.postRequest(this.apiKey, url, params, accessToken); Gtt gtt = new Gtt(); gtt.id = jsonObject.getJSONObject("data").getInt("id"); - System.out.println(gtt); + log.info("gtt : {}",gtt); return gtt; } catch (Exception | SmartAPIException e) { - System.out.println(e.getMessage()); + log.error(e.getMessage()); return null; } } /** * Get Gtt Rule Details. - * + * * @param id is gtt rule id. * @return returns the details of gtt rule. */ @@ -649,11 +681,11 @@ public JSONObject gttRuleDetails(Integer id) { String url = routes.get("api.gtt.details"); JSONObject response = smartAPIRequestHandler.postRequest(this.apiKey, url, params, accessToken); - System.out.println(response); + log.info("response : {}",response); return response.getJSONObject("data"); } catch (Exception | SmartAPIException e) { - System.out.println(e.getMessage()); + log.error(e.getMessage()); return null; } @@ -661,7 +693,7 @@ public JSONObject gttRuleDetails(Integer id) { /** * Get Gtt Rule Details. - * + * * @param status is list of gtt rule status. * @param page is no of page * @param count is the count of gtt rules @@ -676,10 +708,10 @@ public JSONArray gttRuleList(List status, Integer page, Integer count) { String url = routes.get("api.gtt.list"); JSONObject response = smartAPIRequestHandler.postRequest(this.apiKey, url, params, accessToken); - System.out.println(response); + log.info("response : {}",response); return response.getJSONArray("data"); } catch (Exception | SmartAPIException e) { - System.out.println(e.getMessage()); + log.error(e.getMessage()); return null; } @@ -687,27 +719,87 @@ public JSONArray gttRuleList(List status, Integer page, Integer count) { /** * Get Historic Data. - * + * * @param params is historic data params. * @return returns the details of historic data. */ - public String candleData(JSONObject params) { + public JSONArray candleData(JSONObject params) { try { String url = routes.get("api.candle.data"); JSONObject response = smartAPIRequestHandler.postRequest(this.apiKey, url, params, accessToken); - System.out.println(response); - return response.getString("data"); + log.info("response : {}",response); + return response.getJSONArray("data"); } catch (Exception | SmartAPIException e) { - System.out.println(e.getMessage()); + log.error(e.getMessage()); return null; } } + public JSONArray oiData(JSONObject params) { + try { + String url = routes.get("api.oi.data"); + JSONObject response = smartAPIRequestHandler.postRequest(this.apiKey, url, params, accessToken); + log.info("response : {}",response); + return response.getJSONArray("data"); + } catch (Exception | SmartAPIException e) { + log.error(e.getMessage()); + return null; + } + } + + /** + + * Get Search Script Data. + * + * @param payload is Search Script params. + * @return returns the details of Search Script data. + */ + + public String getSearchScrip(JSONObject payload) throws SmartAPIException, IOException { + try { + String url = routes.get("api.search.script.data"); + return smartAPIRequestHandler.postRequestJSONObject(this.apiKey, url, payload, accessToken); + }catch (IOException ex) { + log.error("{} while generating session {}", IO_EXCEPTION_OCCURRED, ex.getMessage()); + throw new IOException(String.format("%s in generating Session %s", IO_EXCEPTION_ERROR_MSG, ex.getMessage())); + } catch (JSONException ex) { + log.error("{} while generating session {}", JSON_EXCEPTION_OCCURRED, ex.getMessage()); + throw new JSONException(String.format("%s in generating Session %s", JSON_EXCEPTION_ERROR_MSG, ex.getMessage())); + } catch (SmartAPIException ex) { + log.error("{} while generating session {}", SMART_API_EXCEPTION_OCCURRED, ex.toString()); + throw new SmartAPIException(String.format("%s in generating Session %s", SMART_API_EXCEPTION_ERROR_MSG, ex)); + } + } + +/** + * Get Market Data. + * + * @param params is market data params. + * @return returns the details of market data. + */ + public JSONObject marketData(JSONObject params) throws SmartAPIException, IOException { + try{ + String url = routes.get("api.market.data"); + JSONObject response = smartAPIRequestHandler.postRequest(this.apiKey, url, params, accessToken); + return response.getJSONObject("data"); + }catch (SmartAPIException ex) { + log.error("{} while placing order {}", SMART_API_EXCEPTION_OCCURRED, ex.toString()); + throw new SmartAPIException(String.format("%s in placing order %s", SMART_API_EXCEPTION_ERROR_MSG, ex)); + } catch (IOException ex) { + log.error("{} while placing order {}", IO_EXCEPTION_OCCURRED, ex.getMessage()); + throw new IOException(String.format("%s in placing order %s", IO_EXCEPTION_ERROR_MSG, ex.getMessage())); + } catch (JSONException ex) { + log.error("{} while placing order {}", JSON_EXCEPTION_OCCURRED, ex.getMessage()); + throw new JSONException(String.format("%s in placing order %s", JSON_EXCEPTION_ERROR_MSG, ex.getMessage())); + + } + } + /** * Logs out user by invalidating the access token. - * + * * @return JSONObject which contains status - * + * */ public JSONObject logout() { @@ -718,9 +810,267 @@ public JSONObject logout() { JSONObject response = smartAPIRequestHandler.postRequest(this.apiKey, url, params, accessToken); return response; } catch (Exception | SmartAPIException e) { - System.out.println(e.getMessage()); + log.error(e.getMessage()); return null; } } + /** + * Get Margin Data. + * + * @param marginParams is margin data params. + * @return returns the response of margin data. + */ + public JSONObject getMarginDetails(List marginParams) throws IOException, SmartAPIException { + try { + JSONArray positionsArray = new JSONArray(); + + for (MarginParams params : marginParams) { + JSONObject position = new JSONObject(); + position.put("exchange", params.exchange); + position.put("qty", params.quantity); + position.put("price", params.price); + position.put("productType", params.productType); + position.put("token", params.token); + position.put("tradeType", params.tradeType); + positionsArray.put(position); + } + + JSONObject requestBody = new JSONObject(); + requestBody.put("positions", positionsArray); + + String url = routes.get("api.margin.batch"); + JSONObject response = smartAPIRequestHandler.postRequest(this.apiKey, url, requestBody, accessToken); + return response; + } catch (SmartAPIException ex) { + log.error("{} while fetching margin data {}", SMART_API_EXCEPTION_OCCURRED, ex.toString()); + throw new SmartAPIException(String.format("%s while fetching margin data %s", SMART_API_EXCEPTION_ERROR_MSG, ex)); + } catch (IOException ex) { + log.error("{} while fetching margin data {}", IO_EXCEPTION_OCCURRED, ex.getMessage()); + throw new IOException(String.format("%s while fetching margin data %s", IO_EXCEPTION_ERROR_MSG, ex.getMessage())); + } catch (JSONException ex) { + log.error("{} while fetching margin data {}", JSON_EXCEPTION_OCCURRED, ex.getMessage()); + throw new JSONException(String.format("%s while fetching margin data %s", JSON_EXCEPTION_ERROR_MSG, ex.getMessage())); + + } + } + + /** Get Individual Order Details + * + * @return JSONObject which contains order details from Smart API + * + */ + public JSONObject getIndividualOrderDetails(String orderId) throws IOException, SmartAPIException { + try { + String url = routes.get("api.individual.order").concat(orderId); + return smartAPIRequestHandler.getRequest(this.apiKey, url, accessToken); + } catch (SmartAPIException ex) { + log.error("{} while getting individual order {}", SMART_API_EXCEPTION_OCCURRED, ex.toString()); + throw new SmartAPIException(String.format("%s in getting individual order %s", SMART_API_EXCEPTION_ERROR_MSG, ex)); + } catch (IOException ex) { + log.error("{} while getting individual order {}", IO_EXCEPTION_OCCURRED, ex.getMessage()); + throw new IOException(String.format("%s while fetching margin data %s", IO_EXCEPTION_ERROR_MSG, ex.getMessage())); + } catch (JSONException ex) { + log.error("{} while getting individual order {}", JSON_EXCEPTION_OCCURRED, ex.getMessage()); + throw new JSONException(String.format("%s while fetching margin data %s", JSON_EXCEPTION_ERROR_MSG, ex.getMessage())); + } + } + + + public JSONObject estimateCharges(List estimateChargesParams) throws IOException, SmartAPIException { + try { + JSONArray ordersArray = new JSONArray(); + + for (EstimateChargesParams params : estimateChargesParams) { + JSONObject order = new JSONObject(); + order.put("product_type", params.product_type); + order.put("transaction_type", params.transaction_type); + order.put("quantity", params.quantity); + order.put("price", params.price); + order.put("exchange", params.exchange); + order.put("symbol_name", params.symbol_name); + order.put("token", params.token); + ordersArray.put(order); + } + + JSONObject requestBody = new JSONObject(); + requestBody.put("orders", ordersArray); + + String url = routes.get("api.estimateCharges"); + JSONObject response = smartAPIRequestHandler.postRequest(this.apiKey, url, requestBody, accessToken); + return response; + } catch (SmartAPIException ex) { + log.error("{} while fetching estimateCharges data {}", SMART_API_EXCEPTION_OCCURRED, ex.toString()); + throw new SmartAPIException(String.format("%s while fetching estimateCharges data %s", SMART_API_EXCEPTION_ERROR_MSG, ex)); + } catch (IOException ex) { + log.error("{} while fetching estimateCharges data {}", IO_EXCEPTION_OCCURRED, ex.getMessage()); + throw new IOException(String.format("%s while fetching estimateCharges data %s", IO_EXCEPTION_ERROR_MSG, ex.getMessage())); + } catch (JSONException ex) { + log.error("{} while fetching estimateCharges data {}", JSON_EXCEPTION_OCCURRED, ex.getMessage()); + throw new JSONException(String.format("%s while fetching estimateCharges data %s", JSON_EXCEPTION_ERROR_MSG, ex.getMessage())); + + } + } + + public JSONObject verifyDis(JSONObject params) throws SmartAPIException, IOException { + try{ + String url = routes.get("api.verifyDis"); + JSONObject response = smartAPIRequestHandler.postRequest(this.apiKey, url, params, accessToken); + return response; + }catch (SmartAPIException ex) { + log.error("{} while verifyDis {}", SMART_API_EXCEPTION_OCCURRED, ex.toString()); + throw new SmartAPIException(String.format("%s in verifyDis %s", SMART_API_EXCEPTION_ERROR_MSG, ex)); + } catch (IOException ex) { + log.error("{} while verifyDis {}", IO_EXCEPTION_OCCURRED, ex.getMessage()); + throw new IOException(String.format("%s in verifyDis %s", IO_EXCEPTION_ERROR_MSG, ex.getMessage())); + } catch (JSONException ex) { + log.error("{} while verifyDis {}", JSON_EXCEPTION_OCCURRED, ex.getMessage()); + throw new JSONException(String.format("%s in verifyDis %s", JSON_EXCEPTION_ERROR_MSG, ex.getMessage())); + + } + } + + public JSONObject generateTPIN(JSONObject params) throws SmartAPIException, IOException { + try{ + String url = routes.get("api.generateTPIN"); + JSONObject response = smartAPIRequestHandler.postRequest(this.apiKey, url, params, accessToken); + return response; + }catch (SmartAPIException ex) { + log.error("{} while generateTPIN {}", SMART_API_EXCEPTION_OCCURRED, ex.toString()); + throw new SmartAPIException(String.format("%s in generateTPIN %s", SMART_API_EXCEPTION_ERROR_MSG, ex)); + } catch (IOException ex) { + log.error("{} while generateTPIN {}", IO_EXCEPTION_OCCURRED, ex.getMessage()); + throw new IOException(String.format("%s in generateTPIN %s", IO_EXCEPTION_ERROR_MSG, ex.getMessage())); + } catch (JSONException ex) { + log.error("{} while generateTPIN {}", JSON_EXCEPTION_OCCURRED, ex.getMessage()); + throw new JSONException(String.format("%s in generateTPIN %s", JSON_EXCEPTION_ERROR_MSG, ex.getMessage())); + + } + } + + public JSONObject getTranStatus(JSONObject params) throws SmartAPIException, IOException { + try{ + String url = routes.get("api.getTranStatus"); + JSONObject response = smartAPIRequestHandler.postRequest(this.apiKey, url, params, accessToken); + return response; + }catch (SmartAPIException ex) { + log.error("{} while getTranStatus {}", SMART_API_EXCEPTION_OCCURRED, ex.toString()); + throw new SmartAPIException(String.format("%s in getTranStatus %s", SMART_API_EXCEPTION_ERROR_MSG, ex)); + } catch (IOException ex) { + log.error("{} while getTranStatus {}", IO_EXCEPTION_OCCURRED, ex.getMessage()); + throw new IOException(String.format("%s in getTranStatus %s", IO_EXCEPTION_ERROR_MSG, ex.getMessage())); + } catch (JSONException ex) { + log.error("{} while getTranStatus {}", JSON_EXCEPTION_OCCURRED, ex.getMessage()); + throw new JSONException(String.format("%s in getTranStatus %s", JSON_EXCEPTION_ERROR_MSG, ex.getMessage())); + + } + } + + public JSONObject optionGreek(JSONObject params) throws SmartAPIException, IOException { + try{ + String url = routes.get("api.optionGreek"); + JSONObject response = smartAPIRequestHandler.postRequest(this.apiKey, url, params, accessToken); + return response; + }catch (SmartAPIException ex) { + log.error("{} while optionGreek {}", SMART_API_EXCEPTION_OCCURRED, ex.toString()); + throw new SmartAPIException(String.format("%s in optionGreek %s", SMART_API_EXCEPTION_ERROR_MSG, ex)); + } catch (IOException ex) { + log.error("{} while optionGreek {}", IO_EXCEPTION_OCCURRED, ex.getMessage()); + throw new IOException(String.format("%s in optionGreek %s", IO_EXCEPTION_ERROR_MSG, ex.getMessage())); + } catch (JSONException ex) { + log.error("{} while optionGreek {}", JSON_EXCEPTION_OCCURRED, ex.getMessage()); + throw new JSONException(String.format("%s in optionGreek %s", JSON_EXCEPTION_ERROR_MSG, ex.getMessage())); + + } + } + + public JSONObject gainersLosers(JSONObject params) throws SmartAPIException, IOException { + try{ + String url = routes.get("api.gainersLosers"); + JSONObject response = smartAPIRequestHandler.postRequest(this.apiKey, url, params, accessToken); + return response; + }catch (SmartAPIException ex) { + log.error("{} while gainersLosers {}", SMART_API_EXCEPTION_OCCURRED, ex.toString()); + throw new SmartAPIException(String.format("%s in gainersLosers %s", SMART_API_EXCEPTION_ERROR_MSG, ex)); + } catch (IOException ex) { + log.error("{} while gainersLosers {}", IO_EXCEPTION_OCCURRED, ex.getMessage()); + throw new IOException(String.format("%s in gainersLosers %s", IO_EXCEPTION_ERROR_MSG, ex.getMessage())); + } catch (JSONException ex) { + log.error("{} while gainersLosers {}", JSON_EXCEPTION_OCCURRED, ex.getMessage()); + throw new JSONException(String.format("%s in gainersLosers %s", JSON_EXCEPTION_ERROR_MSG, ex.getMessage())); + + } + } + + public JSONObject putCallRatio() throws IOException, SmartAPIException { + try { + String url = routes.get("api.putCallRatio"); + JSONObject response = smartAPIRequestHandler.getRequest(this.apiKey, url, accessToken); + return response; + } catch (SmartAPIException ex) { + log.error("{} while getting putCallRatio {}", SMART_API_EXCEPTION_OCCURRED, ex.toString()); + throw new SmartAPIException(String.format("%s in getting putCallRatio %s", SMART_API_EXCEPTION_ERROR_MSG, ex)); + } catch (IOException ex) { + log.error("{} while getting putCallRatio {}", IO_EXCEPTION_OCCURRED, ex.getMessage()); + throw new IOException(String.format("%s while fetching putCallRatio data %s", IO_EXCEPTION_ERROR_MSG, ex.getMessage())); + } catch (JSONException ex) { + log.error("{} while getting putCallRatio {}", JSON_EXCEPTION_OCCURRED, ex.getMessage()); + throw new JSONException(String.format("%s while fetching putCallRatio data %s", JSON_EXCEPTION_ERROR_MSG, ex.getMessage())); + } + } + + public JSONObject nseIntraday() throws IOException, SmartAPIException { + try { + String url = routes.get("api.nseIntraday"); + JSONObject response = smartAPIRequestHandler.getRequest(this.apiKey, url, accessToken); + return response; + } catch (SmartAPIException ex) { + log.error("{} while getting nseIntraday {}", SMART_API_EXCEPTION_OCCURRED, ex.toString()); + throw new SmartAPIException(String.format("%s in getting nseIntraday %s", SMART_API_EXCEPTION_ERROR_MSG, ex)); + } catch (IOException ex) { + log.error("{} while getting nseIntraday {}", IO_EXCEPTION_OCCURRED, ex.getMessage()); + throw new IOException(String.format("%s while fetching nseIntraday data %s", IO_EXCEPTION_ERROR_MSG, ex.getMessage())); + } catch (JSONException ex) { + log.error("{} while getting nseIntraday {}", JSON_EXCEPTION_OCCURRED, ex.getMessage()); + throw new JSONException(String.format("%s while fetching nseIntraday data %s", JSON_EXCEPTION_ERROR_MSG, ex.getMessage())); + } + } + + public JSONObject bseIntraday() throws IOException, SmartAPIException { + try { + String url = routes.get("api.bseIntraday"); + JSONObject response = smartAPIRequestHandler.getRequest(this.apiKey, url, accessToken); + return response; + } catch (SmartAPIException ex) { + log.error("{} while getting bseIntraday {}", SMART_API_EXCEPTION_OCCURRED, ex.toString()); + throw new SmartAPIException(String.format("%s in getting bseIntraday %s", SMART_API_EXCEPTION_ERROR_MSG, ex)); + } catch (IOException ex) { + log.error("{} while getting bseIntraday {}", IO_EXCEPTION_OCCURRED, ex.getMessage()); + throw new IOException(String.format("%s while fetching bseIntraday data %s", IO_EXCEPTION_ERROR_MSG, ex.getMessage())); + } catch (JSONException ex) { + log.error("{} while getting bseIntraday {}", JSON_EXCEPTION_OCCURRED, ex.getMessage()); + throw new JSONException(String.format("%s while fetching bseIntraday data %s", JSON_EXCEPTION_ERROR_MSG, ex.getMessage())); + } + } + + public JSONObject oIBuildup(JSONObject params) throws SmartAPIException, IOException { + try{ + String url = routes.get("api.oIBuildup"); + JSONObject response = smartAPIRequestHandler.postRequest(this.apiKey, url, params, accessToken); + return response; + }catch (SmartAPIException ex) { + log.error("{} while oIBuildup {}", SMART_API_EXCEPTION_OCCURRED, ex.toString()); + throw new SmartAPIException(String.format("%s in oIBuildup %s", SMART_API_EXCEPTION_ERROR_MSG, ex)); + } catch (IOException ex) { + log.error("{} while oIBuildup {}", IO_EXCEPTION_OCCURRED, ex.getMessage()); + throw new IOException(String.format("%s in oIBuildup %s", IO_EXCEPTION_ERROR_MSG, ex.getMessage())); + } catch (JSONException ex) { + log.error("{} while oIBuildup {}", JSON_EXCEPTION_OCCURRED, ex.getMessage()); + throw new JSONException(String.format("%s in oIBuildup %s", JSON_EXCEPTION_ERROR_MSG, ex.getMessage())); + + } + } + + } + diff --git a/src/main/java/com/angelbroking/smartapi/http/SmartAPIRequestHandler.java b/src/main/java/com/angelbroking/smartapi/http/SmartAPIRequestHandler.java index f32b3a3d..fefda5eb 100644 --- a/src/main/java/com/angelbroking/smartapi/http/SmartAPIRequestHandler.java +++ b/src/main/java/com/angelbroking/smartapi/http/SmartAPIRequestHandler.java @@ -1,23 +1,10 @@ package com.angelbroking.smartapi.http; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStreamReader; -import java.net.InetAddress; -import java.net.NetworkInterface; -import java.net.Proxy; -import java.net.URL; -import java.util.Enumeration; -import java.util.Map; -import java.util.concurrent.TimeUnit; - -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; - import com.angelbroking.smartapi.SmartConnect; import com.angelbroking.smartapi.http.exceptions.SmartAPIException; - +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.slf4j.Slf4j; import okhttp3.FormBody; import okhttp3.HttpUrl; import okhttp3.MediaType; @@ -26,10 +13,25 @@ import okhttp3.RequestBody; import okhttp3.Response; import okhttp3.logging.HttpLoggingInterceptor; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.net.Proxy; +import java.net.URL; +import java.util.Enumeration; +import java.util.Map; +import java.util.concurrent.TimeUnit; /** * Request handler for all Http requests */ +@Slf4j public class SmartAPIRequestHandler { private OkHttpClient client; @@ -105,10 +107,10 @@ public JSONObject apiHeaders() { String sourceID = "WEB"; headers.put("sourceID", sourceID); - System.out.print(headers); + log.info("headers : {}",headers); return headers; } catch (Exception e) { - System.out.println(e.getMessage()); + log.error(e.getMessage()); return null; } @@ -130,9 +132,22 @@ public JSONObject postRequest(String apiKey, String url, JSONObject params) throws IOException, JSONException, SmartAPIException { Request request = createPostRequest(apiKey, url, params); - Response response = client.newCall(request).execute(); - String body = response.body().string(); - return new SmartAPIResponseHandler().handle(response, body); + try{ + Response response = client.newCall(request).execute(); + String body = response.body().string(); + ObjectMapper objectMapper = new ObjectMapper(); + JsonNode jsonNode = objectMapper.readTree(body); + if(jsonNode.get("status") == null){ + log.error("Error in POST request. Request URL: {}, Request Headers: {}, Request Body: {},Response : {}", + url, request.headers(), params,body); + } + return new SmartAPIResponseHandler().handle(response, body); + } + catch (Exception e){ + log.error("Error in POST request. Request URL: {}, Request Headers: {}, Request Body: {},Response : {}", + url, request.headers(), params,e.getMessage()); + throw e; + } } @@ -152,9 +167,22 @@ public JSONObject postRequest(String apiKey, String url, JSONObject params) public JSONObject postRequest(String apiKey, String url, JSONObject params, String accessToken) throws IOException, SmartAPIException, JSONException { Request request = createPostRequest(apiKey, url, params, accessToken); - Response response = client.newCall(request).execute(); - String body = response.body().string(); - return new SmartAPIResponseHandler().handle(response, body); + try{ + Response response = client.newCall(request).execute(); + String body = response.body().string(); + ObjectMapper objectMapper = new ObjectMapper(); + JsonNode jsonNode = objectMapper.readTree(body); + if(jsonNode.get("status") == null){ + log.error("Error in POST request. Request URL: {}, Request Headers: {}, Request Body: {},Response : {}", + url, request.headers(), params,body); + } + return new SmartAPIResponseHandler().handle(response, body); + } + catch (Exception e){ + log.error("Error in POST request. Request URL: {}, Request Headers: {}, Request Body: {},Response : {}", + url, request.headers(), params,e.getMessage()); + throw e; + } } /** @@ -240,9 +268,22 @@ public JSONObject deleteRequest(String url, Map params, String a public JSONObject getRequest(String apiKey, String url, String accessToken) throws IOException, SmartAPIException, JSONException { Request request = createGetRequest(apiKey, url, accessToken); - Response response = client.newCall(request).execute(); - String body = response.body().string(); - return new SmartAPIResponseHandler().handle(response, body); + try { + Response response = client.newCall(request).execute(); + String body = response.body().string(); + ObjectMapper objectMapper = new ObjectMapper(); + JsonNode jsonNode = objectMapper.readTree(body); + if(jsonNode.get("status") == null){ + log.error("Error in GET request. Request URL: {}, Request Headers: {},Response : {}", + url, request.headers(),body); + } + return new SmartAPIResponseHandler().handle(response, body); + } + catch (Exception e){ + log.error("Error in POST request. Request URL: {}, Request Headers: {},Response : {}", + url, request.headers(),e.getMessage()); + throw e; + } } /** @@ -317,8 +358,8 @@ public Request createPostRequest(String apiKey, String url, JSONObject params) { .header("X-SourceID", apiheader.getString("sourceID")).build(); return request; } catch (Exception e) { - System.out.println("exception createPostRequest"); - System.out.println(e.getMessage()); + log.error("exception createPostRequest"); + log.error(e.getMessage()); return null; } } @@ -350,7 +391,7 @@ public Request createPostRequest(String apiKey, String url, JSONObject params, S .header("X-SourceID", apiheader.getString("sourceID")).build(); return request; } catch (Exception e) { - System.out.println(e.getMessage()); + log.error(e.getMessage()); return null; } } @@ -374,6 +415,40 @@ public Request createJsonPostRequest(String url, JSONArray jsonArray, String api return request; } + /** + * Makes a POST request. + * + * @return JSONObject which is received by Smart API Trade. + * @param url is the endpoint to which request has to be sent. + * @param apiKey is the api key of the Smart API Connect app. + * @param accessToken is the access token obtained after successful login + * process. + * @param params is the map of params which has to be sent in the body. + * @throws IOException is thrown when there is a connection related error. + * @throws SmartAPIException is thrown for all Smart API Trade related errors. + * @throws JSONException is thrown for parsing errors. + */ + public String postRequestJSONObject(String apiKey, String url, JSONObject params, String accessToken) + throws IOException, SmartAPIException, JSONException { + Request request = createPostRequest(apiKey, url, params, accessToken); + try{ + Response response = client.newCall(request).execute(); + String body = response.body().string(); + ObjectMapper objectMapper = new ObjectMapper(); + JsonNode jsonNode = objectMapper.readTree(body); + if(jsonNode.get("status") == null){ + log.error("Error in POST request. Request URL: {}, Request Headers: {}, Request Body: {},Response : {}", + url, request.headers(), params,body); + } + return new SmartAPIResponseHandler().handler(response, body); + } + catch (Exception e){ + log.error("Error in POST request. Request URL: {}, Request Headers: {}, Request Body: {},Response : {}", + url, request.headers(), params,e.getMessage()); + throw e; + } + } + /** * Creates a PUT request. * diff --git a/src/main/java/com/angelbroking/smartapi/http/SmartAPIResponseHandler.java b/src/main/java/com/angelbroking/smartapi/http/SmartAPIResponseHandler.java index 3beeabad..363eb059 100644 --- a/src/main/java/com/angelbroking/smartapi/http/SmartAPIResponseHandler.java +++ b/src/main/java/com/angelbroking/smartapi/http/SmartAPIResponseHandler.java @@ -1,7 +1,14 @@ package com.angelbroking.smartapi.http; import java.io.IOException; - +import java.util.List; + +import com.angelbroking.smartapi.http.exceptions.ApiKeyException; +import com.angelbroking.smartapi.models.SearchScripResponseDTO; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.slf4j.Slf4j; +import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; @@ -17,22 +24,26 @@ import okhttp3.Response; +import static com.angelbroking.smartapi.utils.Constants.APIKEY_EXCEPTION_MESSAGE; +import static com.angelbroking.smartapi.utils.Constants.TOKEN_EXCEPTION_MESSAGE; + /** * Response handler for handling all the responses. */ +@Slf4j public class SmartAPIResponseHandler { public JSONObject handle(Response response, String body) throws IOException, SmartAPIException, JSONException { - System.out.println("***************************"); + log.info("***************************"); if (response.header("Content-Type").contains("json")) { JSONObject jsonObject = new JSONObject(body); - + // if (jsonObject.optString("data") == null || jsonObject.optString("data") == "") { - if (!jsonObject.has("status") || jsonObject.has("success")) { + if (!jsonObject.has("status") || jsonObject.has("success")) { if (jsonObject.has("errorcode")) { throw dealWithException(jsonObject, jsonObject.getString("errorcode")); } else if (jsonObject.has("errorCode")) { - + throw dealWithException(jsonObject, jsonObject.getString("errorCode")); } } @@ -58,8 +69,9 @@ private SmartAPIException dealWithException(JSONObject jsonObject, String code) return new TokenException(jsonObject.getString("message"), code); case "AG8001": - case "AG8002": - return new DataException(jsonObject.getString("message"), code); + return new TokenException(TOKEN_EXCEPTION_MESSAGE, code); + case "AG8002": + return new DataException(jsonObject.getString("message"), code); case "AB1004": case "AB2000": @@ -87,10 +99,63 @@ private SmartAPIException dealWithException(JSONObject jsonObject, String code) case "AB1001": case "AB1011": return new PermissionException(jsonObject.getString("message"), code); - + case "AG8004": + return new ApiKeyException(APIKEY_EXCEPTION_MESSAGE, code); default: return new SmartAPIException(jsonObject.getString("data not found")); } } + public String handler(Response response, String body) throws SmartAPIException, JSONException, IOException { + if (response.code() == 200) { + return handleResponse(response,body); + } else if (response.code() == 400){ + log.error("Bad request. Please provide valid input"); + return "Bad request. Please provide valid input"; + }else { + log.error("Response or response body is null."); + throw new IllegalArgumentException("Response or response body is null."); + } + } + + private String handleResponse(Response response, String body) throws SmartAPIException, IOException { + try { + JSONObject responseBodyJson = new JSONObject(body); + if(responseBodyJson.getBoolean("status")) { + JSONArray dataArray = responseBodyJson.optJSONArray("data"); + if (dataArray != null && dataArray.length() > 0) { + List stockDTOList = parseStockDTOList(dataArray); + + StringBuilder result = new StringBuilder(); + result.append("Search successful. Found ").append(stockDTOList.size()).append(" trading symbols for the given query:\n"); + + int index = 1; + for (SearchScripResponseDTO stockDTO : stockDTOList) { + result.append(index).append(". exchange: ").append(stockDTO.getExchange()).append(", tradingsymbol: ").append(stockDTO.getTradingSymbol()).append(", symboltoken: ").append(stockDTO.getSymbolToken()).append("\n"); + index++; + } + return result.toString(); + } else { + return "Search successful. No matching trading symbols found for the given query."; + } + }else { + return String.valueOf(handle(response,body)); + } + + } catch (JSONException e) { + log.error("Error parsing response body as JSON.", e.getMessage()); + throw new SmartAPIException("Error parsing response body as JSON."); + } + } + + private List parseStockDTOList(JSONArray dataArray) throws JSONException, SmartAPIException { + ObjectMapper objectMapper = new ObjectMapper(); + try { + return objectMapper.readValue(dataArray.toString(), new TypeReference>() { + }); + } catch (IOException e) { + log.error("Error parsing JSON data array.", e); + throw new SmartAPIException("Error parsing JSON data array."); + } + } } diff --git a/src/main/java/com/angelbroking/smartapi/http/exceptions/ApiKeyException.java b/src/main/java/com/angelbroking/smartapi/http/exceptions/ApiKeyException.java new file mode 100644 index 00000000..0a7c38fc --- /dev/null +++ b/src/main/java/com/angelbroking/smartapi/http/exceptions/ApiKeyException.java @@ -0,0 +1,14 @@ +package com.angelbroking.smartapi.http.exceptions; + +/** + * Exception raised when invalid API Key is provided for Smart API trade. + */ + +public class ApiKeyException extends SmartAPIException { + + // initialize 2fa exception and call constructor of Base Exception + public ApiKeyException(String message, String code){ + super(message, code); + } +} + diff --git a/src/main/java/com/angelbroking/smartapi/models/EstimateChargesParams.java b/src/main/java/com/angelbroking/smartapi/models/EstimateChargesParams.java new file mode 100644 index 00000000..955140d2 --- /dev/null +++ b/src/main/java/com/angelbroking/smartapi/models/EstimateChargesParams.java @@ -0,0 +1,12 @@ +package com.angelbroking.smartapi.models; + +public class EstimateChargesParams { + + public String product_type; + public String transaction_type; + public String quantity; + public String price; + public String exchange; + public String symbol_name; + public String token; +} diff --git a/src/main/java/com/angelbroking/smartapi/models/MarginParams.java b/src/main/java/com/angelbroking/smartapi/models/MarginParams.java new file mode 100644 index 00000000..a5a8f25f --- /dev/null +++ b/src/main/java/com/angelbroking/smartapi/models/MarginParams.java @@ -0,0 +1,38 @@ +package com.angelbroking.smartapi.models; + +/** + * A wrapper class for margin params to get the margin using smartAPI margin url + */ + +public class MarginParams { + + /** + * Exchange in which instrument is listed (NSE, BSE, NFO, BFO, CDS, MCX). + */ + public String exchange; + + /** + * Quantity to transact + */ + public Integer quantity; + + + public Double price; + + /** + * producttype code (NRML, MIS, CNC, NRML, MARGIN, BO, CO). + */ + public String productType; + + /** + * symboltoken of the instrument. + */ + public String token; + + /** + * Buy or Sell + */ + public String tradeType; + + +} diff --git a/src/main/java/com/angelbroking/smartapi/models/Order.java b/src/main/java/com/angelbroking/smartapi/models/Order.java index 3f473f96..f12477ea 100644 --- a/src/main/java/com/angelbroking/smartapi/models/Order.java +++ b/src/main/java/com/angelbroking/smartapi/models/Order.java @@ -109,6 +109,9 @@ public class Order { @SerializedName("filltime") public String fillTime; + @SerializedName("uniqueorderid") + public String uniqueOrderId; + @Override public String toString() { return "Order [disclosedQuantity=" + disclosedQuantity + ", duration=" + duration + ", tradingSymbol=" @@ -122,7 +125,7 @@ public String toString() { + instrumentType + ", strikePrice=" + strikePrice + ", optionType=" + optionType + ", expiryDate=" + expiryDate + ", lotSize=" + lotSize + ", cancelSize=" + cancelSize + ", filledShares=" + filledShares + ", orderStatus=" + orderStatus + ", unfilledShares=" + unfilledShares + ", fillId=" + fillId - + ", fillTime=" + fillTime + "]"; + + ", fillTime=" + fillTime + ", uniqueorderid=" + uniqueOrderId + "]"; } } diff --git a/src/main/java/com/angelbroking/smartapi/models/SearchScripResponseDTO.java b/src/main/java/com/angelbroking/smartapi/models/SearchScripResponseDTO.java new file mode 100644 index 00000000..6f5ec17a --- /dev/null +++ b/src/main/java/com/angelbroking/smartapi/models/SearchScripResponseDTO.java @@ -0,0 +1,18 @@ +package com.angelbroking.smartapi.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +@Data +public class SearchScripResponseDTO { + + @JsonProperty("tradingsymbol") + private String tradingSymbol; + + @JsonProperty("exchange") + private String exchange; + + @JsonProperty("symboltoken") + private String symbolToken; + +} diff --git a/src/main/java/com/angelbroking/smartapi/orderupdate/OrderUpdateListner.java b/src/main/java/com/angelbroking/smartapi/orderupdate/OrderUpdateListner.java new file mode 100644 index 00000000..f841c729 --- /dev/null +++ b/src/main/java/com/angelbroking/smartapi/orderupdate/OrderUpdateListner.java @@ -0,0 +1,12 @@ +package com.angelbroking.smartapi.orderupdate; + +import com.angelbroking.smartapi.smartstream.models.SmartStreamError; + +public interface OrderUpdateListner { + void onConnected(); + void onDisconnected(); + void onError(SmartStreamError error); + void onPong(); + + void onOrderUpdate(String data); +} diff --git a/src/main/java/com/angelbroking/smartapi/orderupdate/OrderUpdateServiceImpl.java b/src/main/java/com/angelbroking/smartapi/orderupdate/OrderUpdateServiceImpl.java new file mode 100644 index 00000000..5baf82b8 --- /dev/null +++ b/src/main/java/com/angelbroking/smartapi/orderupdate/OrderUpdateServiceImpl.java @@ -0,0 +1,32 @@ +package com.angelbroking.smartapi.orderupdate; + +import com.angelbroking.smartapi.smartstream.models.SmartStreamError; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class OrderUpdateServiceImpl implements OrderUpdateListner{ + @Override + public void onConnected() { + // TODO Auto-generated method stub + } + + @Override + public void onDisconnected() { + // TODO Auto-generated method stub + } + + @Override + public void onError(SmartStreamError error) { + // TODO Auto-generated method stub + } + + @Override + public void onPong() { + + } + + @Override + public void onOrderUpdate(String data) { + log.info("order data {} ",data); + } +} diff --git a/src/main/java/com/angelbroking/smartapi/orderupdate/OrderUpdateWebsocket.java b/src/main/java/com/angelbroking/smartapi/orderupdate/OrderUpdateWebsocket.java new file mode 100644 index 00000000..14b1713d --- /dev/null +++ b/src/main/java/com/angelbroking/smartapi/orderupdate/OrderUpdateWebsocket.java @@ -0,0 +1,173 @@ +package com.angelbroking.smartapi.orderupdate; + +import com.angelbroking.smartapi.Routes; +import com.angelbroking.smartapi.smartstream.models.SmartStreamError; +import com.angelbroking.smartapi.utils.Utils; +import com.neovisionaries.ws.client.*; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang.StringUtils; + +import java.io.IOException; +import java.time.LocalDateTime; +import java.util.List; +import java.util.Map; +import java.util.Timer; +import java.util.TimerTask; + +@Slf4j +public class OrderUpdateWebsocket { + private static final int pingIntervalInMilliSeconds = 10000; // 10 seconds + private static final String headerAuthorization = "Authorization"; + private static final Integer delayInMilliSeconds = 5000; + private static final Integer periodInMilliSeconds = 5000; + private final Routes routes = new Routes(); + private final String wsuri = routes.getOrderUpdateUri(); + private WebSocket ws; + private String accessToken; + private final OrderUpdateListner orderUpdateListner; + + private Timer pingTimer; + private LocalDateTime lastPongReceivedTime = LocalDateTime.now(); + + /** + * Initializes the OrderUpdateWebsocket. + * + * @param accessToken + * @param orderUpdateListner + */ + public OrderUpdateWebsocket(String accessToken, OrderUpdateListner orderUpdateListner) { + if (StringUtils.isEmpty(accessToken) || Utils.validateInputNullCheck(orderUpdateListner)) { + + throw new IllegalArgumentException( + "clientId, feedToken and SmartStreamListener should not be empty or null"); + } + this.accessToken = accessToken; + this.orderUpdateListner = orderUpdateListner; + + init(); + } + + private void init() { + try { + log.info("inside websocket init"); + log.info("accessToken {} ", accessToken); + log.info("wsuri = {}", wsuri); + ws = new WebSocketFactory() + .setVerifyHostname(false) + .createSocket(wsuri) + .setPingInterval(pingIntervalInMilliSeconds); + ws.addHeader(headerAuthorization, "Bearer " + accessToken); + ws.addListener(getWebsocketAdapter()); + } catch (IOException e) { + if (Utils.validateInputNotNullCheck(orderUpdateListner)) { + orderUpdateListner.onError(getErrorHolder(e)); + } + } + } + + private WebSocketListener getWebsocketAdapter() { + return new WebSocketAdapter() { + @Override + public void onConnected(WebSocket websocket, Map> headers) throws WebSocketException { + orderUpdateListner.onConnected(); + startPingTimer(websocket); + } + + @Override + public void onTextMessage(WebSocket websocket, String text) throws Exception { + try { + orderUpdateListner.onOrderUpdate(text); + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * On disconnection, return statement ensures that the thread ends. + * + * @param websocket + * @param serverCloseFrame + * @param clientCloseFrame + * @param closedByServer + * @throws Exception + */ + @Override + public void onDisconnected(WebSocket websocket, WebSocketFrame serverCloseFrame, + WebSocketFrame clientCloseFrame, boolean closedByServer) { + try { + if (closedByServer) { + reconnect(); + } else { + stopPingTimer(); + orderUpdateListner.onDisconnected(); + } + } catch (Exception e) { + SmartStreamError error = new SmartStreamError(); + error.setException(e); + orderUpdateListner.onError(error); + } + } + + @Override + public void onCloseFrame(WebSocket websocket, WebSocketFrame frame) throws Exception { + super.onCloseFrame(websocket, frame); + } + + @Override + public void onPongFrame(WebSocket websocket, WebSocketFrame frame) throws Exception { + try { + lastPongReceivedTime = LocalDateTime.now(); + orderUpdateListner.onPong(); + } catch (Exception e) { + SmartStreamError error = new SmartStreamError(); + error.setException(e); + orderUpdateListner.onError(error); + } + } + }; + } + + private void startPingTimer(final WebSocket websocket) { + + pingTimer = new Timer(); + pingTimer.scheduleAtFixedRate(new TimerTask() { + @Override + public void run() { + try { + LocalDateTime currentTime = LocalDateTime.now(); + if (lastPongReceivedTime.isBefore(currentTime.minusSeconds(20))) { + websocket.disconnect(); + reconnect(); + } + } catch (Exception e) { + orderUpdateListner.onError(getErrorHolder(e)); + } + } + }, delayInMilliSeconds, periodInMilliSeconds); // run at every 5 second + } + + private void stopPingTimer() { + if (Utils.validateInputNotNullCheck(pingTimer)) { + pingTimer.cancel(); + pingTimer = null; + } + } + + private void reconnect() throws WebSocketException { + log.info("reconnect - started"); + init(); + connect(); + log.info("reconnect - done"); + } + + private SmartStreamError getErrorHolder(Exception e) { + SmartStreamError error = new SmartStreamError(); + error.setException(e); + return error; + } + + public void connect() throws WebSocketException { + ws.connect(); + log.info("connected to uri: {}", wsuri); + } +} diff --git a/src/main/java/com/angelbroking/smartapi/sample/Test.java b/src/main/java/com/angelbroking/smartapi/sample/APITest.java similarity index 54% rename from src/main/java/com/angelbroking/smartapi/sample/Test.java rename to src/main/java/com/angelbroking/smartapi/sample/APITest.java index 935a4edc..01a383ae 100644 --- a/src/main/java/com/angelbroking/smartapi/sample/Test.java +++ b/src/main/java/com/angelbroking/smartapi/sample/APITest.java @@ -3,8 +3,10 @@ import com.angelbroking.smartapi.SmartConnect; import com.angelbroking.smartapi.http.exceptions.SmartAPIException; import com.angelbroking.smartapi.models.User; +import lombok.extern.slf4j.Slf4j; -public class Test { +@Slf4j +public class APITest { public static void main(String[] args) throws SmartAPIException { try { @@ -19,14 +21,14 @@ public static void main(String[] args) throws SmartAPIException { /* * Set session expiry callback. smartConnect.setSessionExpiryHook(new * SessionExpiryHook() { - * + * * @Override public void sessionExpired() { - * System.out.println("session expired"); } }); - * + * log.info("session expired"); } }); + * * User user = smartConnect.generateSession("", ""); * smartConnect.setAccessToken(user.getAccessToken()); * smartConnect.setUserId(user.getUserId()); - * + * * /* token re-generate */ /* @@ -36,63 +38,98 @@ public static void main(String[] args) throws SmartAPIException { */ Examples examples = new Examples(); - /* System.out.println("getProfile"); */ + /* log.info("getProfile"); */ examples.getProfile(smartConnect); - System.out.println("placeOrder"); + /* log.info("placeOrder"); */ examples.placeOrder(smartConnect); - /* System.out.println("modifyOrder"); */ + /* log.info("modifyOrder"); */ examples.modifyOrder(smartConnect); - /* System.out.println("cancelOrder"); */ + /* log.info("cancelOrder"); */ examples.cancelOrder(smartConnect); - /* System.out.println("getOrder"); */ + /* log.info("getOrder"); */ examples.getOrder(smartConnect); - /* System.out.println("getLTP"); */ + /* log.info("getLTP"); */ examples.getLTP(smartConnect); - /* System.out.println("getTrades"); */ + /* log.info("getTrades"); */ examples.getTrades(smartConnect); - /* System.out.println("getRMS"); */ + /* log.info("getRMS"); */ examples.getRMS(smartConnect); - /* System.out.println("getHolding"); */ + /* log.info("getHolding"); */ examples.getHolding(smartConnect); - /* System.out.println("getPosition"); */ + /* log.info("getAllHolding"); */ + examples.getAllHolding(smartConnect); + + /* log.info("getPosition"); */ examples.getPosition(smartConnect); - /* System.out.println("convertPosition"); */ + /* log.info("convertPosition"); */ examples.convertPosition(smartConnect); - /* System.out.println("createRule"); */ + /* log.info("createRule"); */ examples.createRule(smartConnect); - /* System.out.println("ModifyRule"); */ + /* log.info("ModifyRule"); */ examples.modifyRule(smartConnect); - /* System.out.println("cancelRule"); */ + /* log.info("cancelRule"); */ examples.cancelRule(smartConnect); - /* System.out.println("Rule Details"); */ + /* log.info("Rule Details"); */ examples.ruleDetails(smartConnect); - /* System.out.println("Rule List"); */ + /* log.info("Rule List"); */ examples.ruleList(smartConnect); - /* System.out.println("Historic candle Data"); */ + /* log.info("Historic candle Data"); */ examples.getCandleData(smartConnect); - /* System.out.println("logout"); */ + + /* log.info("Search script api"); */ + examples.getSearchScrip(smartConnect); + + /* log.info("Market Data"); */ + examples.getMarketData(smartConnect); + + + /* log.info("logout"); */ examples.logout(smartConnect); + + /* log.info("Margin Details"); */ + examples.getMarginDetails(smartConnect); + + /* log.info("Individual Order"); */ + examples.getIndividualOrder(smartConnect, "1000051"); + + examples.estimateCharges(smartConnect); + + examples.verifyDis(smartConnect); + + examples.generateTPIN(smartConnect); + + examples.getTranStatus(smartConnect); + + examples.optionGreek(smartConnect); + + examples.gainersLosers(smartConnect); + + examples.putCallRatio(smartConnect); + + examples.oIBuildup(smartConnect); + + /* SmartAPITicker */ String clientId = ""; - User user = smartConnect.generateSession("", ""); + User user = smartConnect.generateSession("", "", ""); String feedToken = user.getFeedToken(); String strWatchListScript = "nse_cm|2885&nse_cm|1594&nse_cm|11536&mcx_fo|221658"; String task = "mw"; @@ -102,16 +139,24 @@ public static void main(String[] args) throws SmartAPIException { /* * String jwtToken = user.getAccessToken(); String apiKey = "smartapi_key"; * String actionType = "subscribe"; String feedType = "order_feed"; - * + * * examples.smartWebSocketUsage(clientId, jwtToken, apiKey, actionType, * feedType); - * + * */ + /* Order Websocket */ + String userClientId = ""; + User userGenerateSession = smartConnect.generateSession("", "", ""); + smartConnect.setAccessToken(userGenerateSession.getAccessToken()); + smartConnect.setUserId(userGenerateSession.getUserId()); + String accessToken = userGenerateSession.getAccessToken(); + + examples.orderUpdateUsage(accessToken); } catch (Exception e) { - System.out.println("Exception: " + e.getMessage()); + log.error("Exception: {}" , e.getMessage()); e.printStackTrace(); } } -} +} \ No newline at end of file diff --git a/src/main/java/com/angelbroking/smartapi/sample/Examples.java b/src/main/java/com/angelbroking/smartapi/sample/Examples.java index 01cfb43a..1a3746e5 100644 --- a/src/main/java/com/angelbroking/smartapi/sample/Examples.java +++ b/src/main/java/com/angelbroking/smartapi/sample/Examples.java @@ -1,30 +1,31 @@ package com.angelbroking.smartapi.sample; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; - -import org.json.JSONArray; -import org.json.JSONObject; - import com.angelbroking.smartapi.SmartConnect; import com.angelbroking.smartapi.http.exceptions.SmartAPIException; -import com.angelbroking.smartapi.models.Gtt; -import com.angelbroking.smartapi.models.GttParams; -import com.angelbroking.smartapi.models.Order; -import com.angelbroking.smartapi.models.OrderParams; -import com.angelbroking.smartapi.models.User; +import com.angelbroking.smartapi.models.*; +import com.angelbroking.smartapi.orderupdate.OrderUpdateListner; +import com.angelbroking.smartapi.orderupdate.OrderUpdateWebsocket; import com.angelbroking.smartapi.smartTicker.SmartWSOnConnect; import com.angelbroking.smartapi.smartTicker.SmartWSOnDisconnect; import com.angelbroking.smartapi.smartTicker.SmartWSOnError; import com.angelbroking.smartapi.smartTicker.SmartWSOnTicks; import com.angelbroking.smartapi.smartTicker.SmartWebsocket; +import com.angelbroking.smartapi.smartstream.models.SmartStreamError; import com.angelbroking.smartapi.ticker.OnConnect; import com.angelbroking.smartapi.ticker.OnTicks; import com.angelbroking.smartapi.ticker.SmartAPITicker; import com.angelbroking.smartapi.utils.Constants; +import lombok.extern.slf4j.Slf4j; +import org.json.JSONArray; +import org.json.JSONObject; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; @SuppressWarnings("unused") +@Slf4j + public class Examples { public void getProfile(SmartConnect smartConnect) throws IOException, SmartAPIException { @@ -35,9 +36,9 @@ public void getProfile(SmartConnect smartConnect) throws IOException, SmartAPIEx /* VARIETY */ /* - * VARIETY_NORMAL: Normal Order (Regular) + * VARIETY_NORMAL: Normal Order (Regular) * VARIETY_AMO: After Market Order - * VARIETY_STOPLOSS: Stop loss order + * VARIETY_STOPLOSS: Stop loss order * VARIETY_ROBO: ROBO (Bracket) Order */ /* TRANSACTION TYPE */ @@ -47,7 +48,7 @@ public void getProfile(SmartConnect smartConnect) throws IOException, SmartAPIEx /* ORDER TYPE */ /* - * ORDER_TYPE_MARKET: Market Order(MKT) + * ORDER_TYPE_MARKET: Market Order(MKT) * ORDER_TYPE_LIMIT: Limit Order(L) * ORDER_TYPE_STOPLOSS_LIMIT: Stop Loss Limit Order(SL) * ORDER_TYPE_STOPLOSS_MARKET: Stop Loss Market Order(SL-M) @@ -55,27 +56,27 @@ public void getProfile(SmartConnect smartConnect) throws IOException, SmartAPIEx /* PRODUCT TYPE */ /* - * PRODUCT_DELIVERY: Cash & Carry for equity (CNC) + * PRODUCT_DELIVERY: Cash & Carry for equity (CNC) * PRODUCT_CARRYFORWARD: Normal - * for futures and options (NRML) + * for futures and options (NRML) * PRODUCT_MARGIN: Margin Delivery - * PRODUCT_INTRADAY: Margin Intraday Squareoff (MIS) + * PRODUCT_INTRADAY: Margin Intraday Squareoff (MIS) * PRODUCT_BO: Bracket Order * (Only for ROBO) */ /* DURATION */ /* - * DURATION_DAY: Valid for a day + * DURATION_DAY: Valid for a day * DURATION_IOC: Immediate or Cancel */ /* EXCHANGE */ /* - * EXCHANGE_BSE: BSE Equity - * EXCHANGE_NSE: NSE Equity - * EXCHANGE_NFO: NSE Future and Options - * EXCHANGE_CDS: NSE Currency + * EXCHANGE_BSE: BSE Equity + * EXCHANGE_NSE: NSE Equity + * EXCHANGE_NFO: NSE Future and Options + * EXCHANGE_CDS: NSE Currency * EXCHANGE_NCDEX: NCDEX Commodity * EXCHANGE_MCX: MCX Commodity */ @@ -85,7 +86,7 @@ public void placeOrder(SmartConnect smartConnect) throws SmartAPIException, IOEx OrderParams orderParams = new OrderParams(); orderParams.variety = Constants.VARIETY_STOPLOSS; - orderParams.quantity = 323; + orderParams.quantity = 1; orderParams.symboltoken = "1660"; orderParams.exchange = Constants.EXCHANGE_NSE; orderParams.ordertype = Constants.ORDER_TYPE_STOPLOSS_LIMIT; @@ -97,7 +98,7 @@ public void placeOrder(SmartConnect smartConnect) throws SmartAPIException, IOEx orderParams.triggerprice = "209"; Order order = smartConnect.placeOrder(orderParams, "STOPLOSS"); - System.out.print(order); + log.info("order : {}",order); } /** Modify order. */ @@ -129,10 +130,7 @@ public void cancelOrder(SmartConnect smartConnect) throws SmartAPIException, IOE /** Get order details */ public void getOrder(SmartConnect smartConnect) throws SmartAPIException, IOException { JSONObject orders = smartConnect.getOrderHistory(smartConnect.getUserId()); - System.out.print(orders); -// for (int i = 0; i < orders.size(); i++) { -// System.out.println(orders.get(i).orderId + " " + orders.get(i).status); -// } + log.info("orders {} ",orders); } /** @@ -166,6 +164,13 @@ public void getHolding(SmartConnect smartConnect) throws SmartAPIException, IOEx JSONObject response = smartConnect.getHolding(); } + /** Get All Holdings */ + public void getAllHolding(SmartConnect smartConnect) throws SmartAPIException, IOException { + // Returns All Holding. + JSONObject response = smartConnect.getAllHolding(); + log.info("response : " , response); + } + /** Get Position */ public void getPosition(SmartConnect smartConnect) throws SmartAPIException, IOException { // Returns Position. @@ -270,9 +275,39 @@ public void getCandleData(SmartConnect smartConnect) throws SmartAPIException, I requestObejct.put("fromdate", "2021-03-08 09:00"); requestObejct.put("todate", "2021-03-09 09:20"); - String response = smartConnect.candleData(requestObejct); + JSONArray response = smartConnect.candleData(requestObejct); } + + /** Search Scrip Data */ + public void getSearchScrip(SmartConnect smartConnect) throws SmartAPIException, IOException { + JSONObject payload = new JSONObject(); + payload.put("exchange", "MCX"); + payload.put("searchscrip", "Crude"); + smartConnect.getSearchScrip(payload); + } + + /** + * Market Data + * To Retrieve Market Data with different modes use. + * e.g: + * payload.put("mode", "FULL"); + * payload.put("mode", "LTP"); + * payload.put("mode", "OHLC"); + */ + public void getMarketData(SmartConnect smartConnect) throws SmartAPIException, IOException { + JSONObject payload = new JSONObject(); + payload.put("mode", "FULL"); // You can change the mode as needed + JSONObject exchangeTokens = new JSONObject(); + JSONArray nseTokens = new JSONArray(); + nseTokens.put("3045"); + exchangeTokens.put("NSE", nseTokens); + payload.put("exchangeTokens", exchangeTokens); + JSONObject response = smartConnect.marketData(payload); + } + + + public void tickerUsage(String clientId, String feedToken, String strWatchListScript, String task) throws SmartAPIException { @@ -281,7 +316,7 @@ public void tickerUsage(String clientId, String feedToken, String strWatchListSc tickerProvider.setOnConnectedListener(new OnConnect() { @Override public void onConnected() { - System.out.println("subscribe() called!"); + log.info("subscribe() called!"); tickerProvider.subscribe(); } }); @@ -289,7 +324,7 @@ public void onConnected() { tickerProvider.setOnTickerArrivalListener(new OnTicks() { @Override public void onTicks(JSONArray ticks) { - System.out.println("ticker data: " + ticks.toString()); + log.info("ticker data: " + ticks.toString()); } }); @@ -303,7 +338,7 @@ public void onTicks(JSONArray ticks) { * method. */ boolean isConnected = tickerProvider.isConnectionOpen(); - System.out.println(isConnected); + log.info("is connected {} ",isConnected); // After using SmartAPI ticker, close websocket connection. // tickerProvider.disconnect(); @@ -327,7 +362,7 @@ public void onConnected() { smartWebsocket.setOnDisconnectedListener(new SmartWSOnDisconnect() { @Override public void onDisconnected() { - System.out.println("onDisconnected"); + log.info("onDisconnected"); } }); @@ -335,24 +370,24 @@ public void onDisconnected() { smartWebsocket.setOnErrorListener(new SmartWSOnError() { @Override public void onError(Exception exception) { - System.out.println("onError: " + exception.getMessage()); + log.info("onError: " + exception.getMessage()); } @Override public void onError(SmartAPIException smartAPIException) { - System.out.println("onError: " + smartAPIException.getMessage()); + log.info("onError: " + smartAPIException.getMessage()); } @Override public void onError(String error) { - System.out.println("onError: " + error); + log.info("onError: " + error); } }); smartWebsocket.setOnTickerArrivalListener(new SmartWSOnTicks() { @Override public void onTicks(JSONArray ticks) { - System.out.println("ticker data: " + ticks.toString()); + log.info("ticker data: " + ticks.toString()); } }); @@ -366,7 +401,7 @@ public void onTicks(JSONArray ticks) { * method. */ boolean isConnected = smartWebsocket.isConnectionOpen(); - System.out.println(isConnected); + log.info("is connected {}",isConnected); // After using SmartAPI ticker, close websocket connection. // smartWebsocket.disconnect(); @@ -379,4 +414,162 @@ public void logout(SmartConnect smartConnect) throws SmartAPIException, IOExcept JSONObject jsonObject = smartConnect.logout(); } + + /** Margin data. */ + public void getMarginDetails(SmartConnect smartConnect) throws SmartAPIException, IOException { + List marginParamsList = new ArrayList<>(); + MarginParams marginParams = new MarginParams(); + marginParams.quantity = 1; + marginParams.token = "12740"; + marginParams.exchange = Constants.EXCHANGE_NSE; + marginParams.productType = Constants.PRODUCT_DELIVERY; + marginParams.price = 0.0; + marginParams.tradeType = Constants.TRADETYPE_BUY; + + marginParamsList.add(marginParams); + JSONObject jsonObject = smartConnect.getMarginDetails(marginParamsList); + log.info("response {} ", jsonObject); + + } + + /** Get Individual Order */ + public void getIndividualOrder(SmartConnect smartConnect, String orderId) throws SmartAPIException, IOException { + JSONObject jsonObject = smartConnect.getIndividualOrderDetails(orderId); + log.info("response {} ", jsonObject); + } + + /** + * Order update websocket + * + * To retrieve order update websocket data + * @param accessToken + */ + public void orderUpdateUsage(String accessToken){ + OrderUpdateWebsocket orderUpdateWebsocket = new OrderUpdateWebsocket(accessToken, new OrderUpdateListner() { + /** + * Check if the websocket is connected or not + */ + @Override + public void onConnected() { + log.info("order update websocket connected"); + } + + /** + * Handle the onDisconnected event + */ + @Override + public void onDisconnected() { + + } + + /** + * Handle the onError event + * @param error + */ + @Override + public void onError(SmartStreamError error) { + + } + + /** + * Handle the onPong event + */ + @Override + public void onPong() { + + } + + /** + * Handle the onOrderUpdate event + * @param data + */ + @Override + public void onOrderUpdate(String data) { + log.info("order update data {} ",data); + } + }); + } + + public void estimateCharges(SmartConnect smartConnect) throws SmartAPIException, IOException { + List estimateChargesParamsList = new ArrayList<>(); + EstimateChargesParams estimate_Charges_Params = new EstimateChargesParams(); + estimate_Charges_Params.product_type = Constants.PRODUCT_DELIVERY; + estimate_Charges_Params.transaction_type = Constants.TRANSACTION_TYPE_BUY; + estimate_Charges_Params.quantity = "10"; + estimate_Charges_Params.price = "800"; + estimate_Charges_Params.exchange = Constants.EXCHANGE_NSE; + estimate_Charges_Params.symbol_name = "745AS33"; + estimate_Charges_Params.token = "17117"; + + estimateChargesParamsList.add(estimate_Charges_Params); + + JSONObject jsonObject = smartConnect.estimateCharges(estimateChargesParamsList); + log.info("response {} ", jsonObject); + } + + public void verifyDis(SmartConnect smartConnect) throws SmartAPIException, IOException { + + JSONObject payload = new JSONObject(); + payload.put("isin", "INE242A01010"); + payload.put("quantity", "1"); + + JSONObject jsonObject = smartConnect.verifyDis(payload); + log.info("response {} ", jsonObject); + } + + public void generateTPIN(SmartConnect smartConnect) throws SmartAPIException, IOException { + + JSONObject payload = new JSONObject(); + payload.put("dpId", "33200"); + payload.put("ReqId", "1431307824801952"); + payload.put("boid", "1203320018563571"); + payload.put("pan", "JZTPS2255C"); + + JSONObject jsonObject = smartConnect.generateTPIN(payload); + log.info("response {} ", jsonObject); + } + + public void getTranStatus(SmartConnect smartConnect) throws SmartAPIException, IOException { + + JSONObject payload = new JSONObject(); + payload.put("ReqId", "1431307824801952"); + + JSONObject jsonObject = smartConnect.getTranStatus(payload); + log.info("response {} ", jsonObject); + } + + public void optionGreek(SmartConnect smartConnect) throws SmartAPIException, IOException { + + JSONObject payload = new JSONObject(); + payload.put("name", "TCS"); + payload.put("expirydate", "25MAR2024"); + + JSONObject jsonObject = smartConnect.optionGreek(payload); + log.info("response {} ", jsonObject); + } + + public void gainersLosers(SmartConnect smartConnect) throws SmartAPIException, IOException { + + JSONObject payload = new JSONObject(); + payload.put("datatype", "PercOIGainers"); + payload.put("expirytype", "NEAR"); + + JSONObject jsonObject = smartConnect.gainersLosers(payload); + log.info("response {} ", jsonObject); + } + + public void putCallRatio(SmartConnect smartConnect) throws SmartAPIException, IOException { + JSONObject response = smartConnect.putCallRatio(); + log.info("response {} ", response); + } + + public void oIBuildup(SmartConnect smartConnect) throws SmartAPIException, IOException { + + JSONObject payload = new JSONObject(); + payload.put("expirytype", "NEAR"); + payload.put("datatype", "Long Built Up"); + + JSONObject jsonObject = smartConnect.oIBuildup(payload); + log.info("response {} ", jsonObject); + } } diff --git a/src/main/java/com/angelbroking/smartapi/sample/LoginWithTOTPSample.java b/src/main/java/com/angelbroking/smartapi/sample/LoginWithTOTPSample.java new file mode 100644 index 00000000..c8b02056 --- /dev/null +++ b/src/main/java/com/angelbroking/smartapi/sample/LoginWithTOTPSample.java @@ -0,0 +1,20 @@ +package com.angelbroking.smartapi.sample; + +import com.angelbroking.smartapi.SmartConnect; +import com.angelbroking.smartapi.models.User; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class LoginWithTOTPSample { + + public static void main(String[] args) { + String clientID = System.getProperty("clientID"); + String clientPass = System.getProperty("clientPass"); + String apiKey = System.getProperty("apiKey"); + String totp = System.getProperty("totp"); + SmartConnect smartConnect = new SmartConnect(apiKey); + User user = smartConnect.generateSession(clientID, clientPass, totp); + String feedToken = user.getFeedToken(); + log.info("feedToken : {}",feedToken); + } +} diff --git a/src/main/java/com/angelbroking/smartapi/smartstream/models/BestTwentyData.java b/src/main/java/com/angelbroking/smartapi/smartstream/models/BestTwentyData.java new file mode 100644 index 00000000..71a498b6 --- /dev/null +++ b/src/main/java/com/angelbroking/smartapi/smartstream/models/BestTwentyData.java @@ -0,0 +1,14 @@ +package com.angelbroking.smartapi.smartstream.models; + +import lombok.*; + +@Setter +@Getter +@NoArgsConstructor +@AllArgsConstructor +@ToString +public class BestTwentyData { + private long quantity = -1; + private long price = -1; + private short numberOfOrders = -1; +} diff --git a/src/main/java/com/angelbroking/smartapi/smartstream/models/Depth.java b/src/main/java/com/angelbroking/smartapi/smartstream/models/Depth.java new file mode 100644 index 00000000..58a67b6c --- /dev/null +++ b/src/main/java/com/angelbroking/smartapi/smartstream/models/Depth.java @@ -0,0 +1,32 @@ +package com.angelbroking.smartapi.smartstream.models; + +import com.angelbroking.smartapi.utils.ByteUtils; +import lombok.Getter; +import lombok.Setter; + +import java.nio.ByteBuffer; + +import static com.angelbroking.smartapi.utils.Constants.*; + +@Getter +@Setter +public class Depth { + private byte subscriptionMode; + private ExchangeType exchangeType; + private TokenID token; + private long exchangeTimeStamp; + private long packetReceivedTime; + private BestTwentyData[] bestTwentyBuyData; + private BestTwentyData[] bestTwentySellData; + + + public Depth(ByteBuffer buffer) { + this.subscriptionMode = buffer.get(SUBSCRIPTION_MODE); + this.token = ByteUtils.getTokenID(buffer); + this.exchangeType = this.token.getExchangeType(); + this.exchangeTimeStamp = buffer.getLong(EXCHANGE_TIMESTAMP_FOR_DEPTH20); + this.packetReceivedTime = buffer.getLong(PACKET_RECEIVED_TIME_FOR_DEPTH20); + this.bestTwentyBuyData = ByteUtils.getBestTwentyBuyData(buffer); + this.bestTwentySellData = ByteUtils.getBestTwentySellData(buffer); + } +} diff --git a/src/main/java/com/angelbroking/smartapi/smartstream/models/ExchangeType.java b/src/main/java/com/angelbroking/smartapi/smartstream/models/ExchangeType.java new file mode 100644 index 00000000..8ce63193 --- /dev/null +++ b/src/main/java/com/angelbroking/smartapi/smartstream/models/ExchangeType.java @@ -0,0 +1,38 @@ +package com.angelbroking.smartapi.smartstream.models; + +import java.util.HashMap; +import java.util.Map; +import java.util.NoSuchElementException; + +public enum ExchangeType { + NSE_CM(1), NSE_FO(2), BSE_CM(3), BSE_FO(4), MCX_FO(5), NCX_FO(7), CDE_FO(13); + + private int val; + private static final Map valToExchangeTypeMap = new HashMap<>(); + + private ExchangeType(int val) { + this.val = val; + } + + static { + valToExchangeTypeMap.put(1, NSE_CM); + valToExchangeTypeMap.put(2, NSE_FO); + valToExchangeTypeMap.put(3, BSE_CM); + valToExchangeTypeMap.put(4, BSE_FO); + valToExchangeTypeMap.put(5, MCX_FO); + valToExchangeTypeMap.put(7, NCX_FO); + valToExchangeTypeMap.put(13, CDE_FO); + } + + public int getVal() { + return this.val; + } + + public static ExchangeType findByValue(int val) { + ExchangeType exchange = valToExchangeTypeMap.get(val); + if (exchange == null) { + throw new NoSuchElementException(String.format("No ExchangeType found with value: %s", val)); + } + return exchange; + } +} diff --git a/src/main/java/com/angelbroking/smartapi/smartstream/models/LTP.java b/src/main/java/com/angelbroking/smartapi/smartstream/models/LTP.java new file mode 100644 index 00000000..4399d957 --- /dev/null +++ b/src/main/java/com/angelbroking/smartapi/smartstream/models/LTP.java @@ -0,0 +1,33 @@ +package com.angelbroking.smartapi.smartstream.models; + +import static com.angelbroking.smartapi.utils.Constants.EXCHANGE_FEED_TIME_OFFSET; +import static com.angelbroking.smartapi.utils.Constants.LAST_TRADED_PRICE_OFFSET; +import static com.angelbroking.smartapi.utils.Constants.SEQUENCE_NUMBER_OFFSET; +import static com.angelbroking.smartapi.utils.Constants.SUBSCRIPTION_MODE; + +import java.nio.ByteBuffer; + +import com.angelbroking.smartapi.utils.ByteUtils; + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class LTP { + private byte subscriptionMode; + private ExchangeType exchangeType; + private TokenID token; + private long sequenceNumber; + private long exchangeFeedTimeEpochMillis; + private long lastTradedPrice; + + public LTP(ByteBuffer buffer) { + this.subscriptionMode = buffer.get(SUBSCRIPTION_MODE); + this.token = ByteUtils.getTokenID(buffer); + this.exchangeType = this.token.getExchangeType(); + this.sequenceNumber = buffer.getLong(SEQUENCE_NUMBER_OFFSET); + this.exchangeFeedTimeEpochMillis = buffer.getLong(EXCHANGE_FEED_TIME_OFFSET); + this.lastTradedPrice = buffer.getLong(LAST_TRADED_PRICE_OFFSET); + } +} diff --git a/src/main/java/com/angelbroking/smartapi/smartstream/models/Quote.java b/src/main/java/com/angelbroking/smartapi/smartstream/models/Quote.java new file mode 100644 index 00000000..f04f4d03 --- /dev/null +++ b/src/main/java/com/angelbroking/smartapi/smartstream/models/Quote.java @@ -0,0 +1,61 @@ +package com.angelbroking.smartapi.smartstream.models; + +import static com.angelbroking.smartapi.utils.Constants.AVG_TRADED_PRICE_OFFSET; +import static com.angelbroking.smartapi.utils.Constants.CLOSE_PRICE_OFFSET; +import static com.angelbroking.smartapi.utils.Constants.EXCHANGE_FEED_TIME_OFFSET; +import static com.angelbroking.smartapi.utils.Constants.EXCHANGE_TYPE; +import static com.angelbroking.smartapi.utils.Constants.HIGH_PRICE_OFFSET; +import static com.angelbroking.smartapi.utils.Constants.LAST_TRADED_PRICE_OFFSET; +import static com.angelbroking.smartapi.utils.Constants.LAST_TRADED_QTY_OFFSET; +import static com.angelbroking.smartapi.utils.Constants.LOW_PRICE_OFFSET; +import static com.angelbroking.smartapi.utils.Constants.OPEN_PRICE_OFFSET; +import static com.angelbroking.smartapi.utils.Constants.SEQUENCE_NUMBER_OFFSET; +import static com.angelbroking.smartapi.utils.Constants.SUBSCRIPTION_MODE; +import static com.angelbroking.smartapi.utils.Constants.TOTAL_BUY_QTY_OFFSET; +import static com.angelbroking.smartapi.utils.Constants.TOTAL_SELL_QTY_OFFSET; +import static com.angelbroking.smartapi.utils.Constants.VOLUME_TRADED_TODAY_OFFSET; + +import java.nio.ByteBuffer; + +import com.angelbroking.smartapi.utils.ByteUtils; + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class Quote { + private byte subscriptionMode; + private ExchangeType exchangeType; + private TokenID token; + private long sequenceNumber; + private long exchangeFeedTimeEpochMillis; + private long lastTradedPrice; + private long lastTradedQty; + private long avgTradedPrice; + private long volumeTradedToday; + private double totalBuyQty; + private double totalSellQty; + private long openPrice; + private long highPrice; + private long lowPrice; + private long closePrice; + + public Quote(ByteBuffer buffer) { + this.subscriptionMode = buffer.get(SUBSCRIPTION_MODE); + this.token = ByteUtils.getTokenID(buffer); + this.exchangeType = this.token.getExchangeType(); + this.sequenceNumber = buffer.getLong(SEQUENCE_NUMBER_OFFSET); + this.exchangeFeedTimeEpochMillis = buffer.getLong(EXCHANGE_FEED_TIME_OFFSET); + this.lastTradedPrice = buffer.getLong(LAST_TRADED_PRICE_OFFSET); + this.lastTradedQty = buffer.getLong(LAST_TRADED_QTY_OFFSET); + this.avgTradedPrice = buffer.getLong(AVG_TRADED_PRICE_OFFSET); + this.volumeTradedToday = buffer.getLong(VOLUME_TRADED_TODAY_OFFSET); + this.totalBuyQty = buffer.getLong(TOTAL_BUY_QTY_OFFSET); + this.totalSellQty = buffer.getLong(TOTAL_SELL_QTY_OFFSET); + this.openPrice = buffer.getLong(OPEN_PRICE_OFFSET); + this.highPrice = buffer.getLong(HIGH_PRICE_OFFSET); + this.lowPrice = buffer.getLong(LOW_PRICE_OFFSET); + this.closePrice = buffer.getLong(CLOSE_PRICE_OFFSET); + } +} diff --git a/src/main/java/com/angelbroking/smartapi/smartstream/models/SmartApiBBSInfo.java b/src/main/java/com/angelbroking/smartapi/smartstream/models/SmartApiBBSInfo.java new file mode 100644 index 00000000..0ea783d0 --- /dev/null +++ b/src/main/java/com/angelbroking/smartapi/smartstream/models/SmartApiBBSInfo.java @@ -0,0 +1,23 @@ +package com.angelbroking.smartapi.smartstream.models; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; + +@Setter +@Getter +@NoArgsConstructor +@AllArgsConstructor +@ToString +public class SmartApiBBSInfo { + public static final int BYTES = (2 * Short.BYTES) + (2 * Long.BYTES); + + // siBbBuySellFlag = 1 buy + // siBbBuySellFlag = 0 sell + private short buySellFlag = -1; + private long quantity = -1; + private long price = -1; + private short numberOfOrders = -1; +} \ No newline at end of file diff --git a/src/main/java/com/angelbroking/smartapi/smartstream/models/SmartStreamAction.java b/src/main/java/com/angelbroking/smartapi/smartstream/models/SmartStreamAction.java new file mode 100644 index 00000000..4091b49e --- /dev/null +++ b/src/main/java/com/angelbroking/smartapi/smartstream/models/SmartStreamAction.java @@ -0,0 +1,24 @@ +package com.angelbroking.smartapi.smartstream.models; + +public enum SmartStreamAction { + SUBS(1), UNSUBS(0); + + private int val; + + private SmartStreamAction(int val) { + this.val = val; + } + + public static SmartStreamAction findByVal(int val) { + for(SmartStreamAction entry : SmartStreamAction.values()) { + if(entry.getVal() == val) { + return entry; + } + } + return null; + } + + public int getVal() { + return this.val; + } +} \ No newline at end of file diff --git a/src/main/java/com/angelbroking/smartapi/smartstream/models/SmartStreamError.java b/src/main/java/com/angelbroking/smartapi/smartstream/models/SmartStreamError.java new file mode 100644 index 00000000..f5ca0e26 --- /dev/null +++ b/src/main/java/com/angelbroking/smartapi/smartstream/models/SmartStreamError.java @@ -0,0 +1,14 @@ +package com.angelbroking.smartapi.smartstream.models; + +public class SmartStreamError { + private Throwable exception; + + public Throwable getException() { + return exception; + } + + public void setException(Throwable exception) { + this.exception = exception; + } + +} diff --git a/src/main/java/com/angelbroking/smartapi/smartstream/models/SmartStreamSubsMode.java b/src/main/java/com/angelbroking/smartapi/smartstream/models/SmartStreamSubsMode.java new file mode 100644 index 00000000..490fb626 --- /dev/null +++ b/src/main/java/com/angelbroking/smartapi/smartstream/models/SmartStreamSubsMode.java @@ -0,0 +1,31 @@ +package com.angelbroking.smartapi.smartstream.models; + +public enum SmartStreamSubsMode { + LTP(1), QUOTE(2), SNAP_QUOTE(3), DEPTH_20(4); + + private static final int SIZE = SmartStreamSubsMode.values().length; + + private int val; + + private SmartStreamSubsMode(int val) { + this.val = val; + } + + public static SmartStreamSubsMode findByVal(int val) { + for(SmartStreamSubsMode entry : SmartStreamSubsMode.values()) { + if(entry.getVal() == val) { + return entry; + } + } + return null; + } + + public static int size() { + return SIZE; + } + + public int getVal() { + return this.val; + } + +} \ No newline at end of file diff --git a/src/main/java/com/angelbroking/smartapi/smartstream/models/SnapQuote.java b/src/main/java/com/angelbroking/smartapi/smartstream/models/SnapQuote.java new file mode 100644 index 00000000..93ec45fa --- /dev/null +++ b/src/main/java/com/angelbroking/smartapi/smartstream/models/SnapQuote.java @@ -0,0 +1,85 @@ +package com.angelbroking.smartapi.smartstream.models; + +import static com.angelbroking.smartapi.utils.Constants.AVG_TRADED_PRICE_OFFSET; +import static com.angelbroking.smartapi.utils.Constants.CLOSE_PRICE_OFFSET; +import static com.angelbroking.smartapi.utils.Constants.EXCHANGE_FEED_TIME_OFFSET; +import static com.angelbroking.smartapi.utils.Constants.HIGH_PRICE_OFFSET; +import static com.angelbroking.smartapi.utils.Constants.LAST_TRADED_PRICE_OFFSET; +import static com.angelbroking.smartapi.utils.Constants.LAST_TRADED_QTY_OFFSET; +import static com.angelbroking.smartapi.utils.Constants.LAST_TRADED_TIMESTAMP_OFFSET; +import static com.angelbroking.smartapi.utils.Constants.LOWER_CIRCUIT_OFFSET; +import static com.angelbroking.smartapi.utils.Constants.LOW_PRICE_OFFSET; +import static com.angelbroking.smartapi.utils.Constants.OPEN_INTEREST_CHANGE_PERC_OFFSET; +import static com.angelbroking.smartapi.utils.Constants.OPEN_INTEREST_OFFSET; +import static com.angelbroking.smartapi.utils.Constants.OPEN_PRICE_OFFSET; +import static com.angelbroking.smartapi.utils.Constants.SEQUENCE_NUMBER_OFFSET; +import static com.angelbroking.smartapi.utils.Constants.SUBSCRIPTION_MODE; +import static com.angelbroking.smartapi.utils.Constants.TOTAL_BUY_QTY_OFFSET; +import static com.angelbroking.smartapi.utils.Constants.TOTAL_SELL_QTY_OFFSET; +import static com.angelbroking.smartapi.utils.Constants.UPPER_CIRCUIT_OFFSET; +import static com.angelbroking.smartapi.utils.Constants.VOLUME_TRADED_TODAY_OFFSET; +import static com.angelbroking.smartapi.utils.Constants.YEARLY_HIGH_PRICE_OFFSET; +import static com.angelbroking.smartapi.utils.Constants.YEARLY_LOW_PRICE_OFFSET; + +import java.nio.ByteBuffer; + +import com.angelbroking.smartapi.utils.ByteUtils; + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class SnapQuote { + private byte subscriptionMode; + private ExchangeType exchangeType; + private TokenID token; + private long sequenceNumber; + private long exchangeFeedTimeEpochMillis; + private long lastTradedPrice; + private long lastTradedQty; + private long avgTradedPrice; + private long volumeTradedToday; + private double totalBuyQty; + private double totalSellQty; + private long openPrice; + private long highPrice; + private long lowPrice; + private long closePrice; + private long lastTradedTimestamp = 0; + private long openInterest = 0; + private double openInterestChangePerc = 0; + private SmartApiBBSInfo[] bestFiveBuy; + private SmartApiBBSInfo[] bestFiveSell; + private long upperCircuit = 0; + private long lowerCircuit = 0; + private long yearlyHighPrice = 0; + private long yearlyLowPrice = 0; + + public SnapQuote(ByteBuffer buffer) { + this.subscriptionMode = buffer.get(SUBSCRIPTION_MODE); + this.token = ByteUtils.getTokenID(buffer); + this.exchangeType = this.token.getExchangeType(); + this.sequenceNumber = buffer.getLong(SEQUENCE_NUMBER_OFFSET); + this.exchangeFeedTimeEpochMillis = buffer.getLong(EXCHANGE_FEED_TIME_OFFSET); + this.lastTradedPrice = buffer.getLong(LAST_TRADED_PRICE_OFFSET); + this.lastTradedQty = buffer.getLong(LAST_TRADED_QTY_OFFSET); + this.avgTradedPrice = buffer.getLong(AVG_TRADED_PRICE_OFFSET); + this.volumeTradedToday = buffer.getLong(VOLUME_TRADED_TODAY_OFFSET); + this.totalBuyQty = buffer.getDouble(TOTAL_BUY_QTY_OFFSET); + this.totalSellQty = buffer.getDouble(TOTAL_SELL_QTY_OFFSET); + this.openPrice = buffer.getLong(OPEN_PRICE_OFFSET); + this.highPrice = buffer.getLong(HIGH_PRICE_OFFSET); + this.lowPrice = buffer.getLong(LOW_PRICE_OFFSET); + this.closePrice = buffer.getLong(CLOSE_PRICE_OFFSET); + this.lastTradedTimestamp = buffer.getLong(LAST_TRADED_TIMESTAMP_OFFSET); + this.openInterest = buffer.getLong(OPEN_INTEREST_OFFSET); + this.openInterestChangePerc = buffer.getDouble(OPEN_INTEREST_CHANGE_PERC_OFFSET); + this.bestFiveBuy = ByteUtils.getBestFiveBuyData(buffer); + this.bestFiveSell = ByteUtils.getBestFiveSellData(buffer); + this.upperCircuit = buffer.getLong(UPPER_CIRCUIT_OFFSET); + this.lowerCircuit = buffer.getLong(LOWER_CIRCUIT_OFFSET); + this.yearlyHighPrice = buffer.getLong(YEARLY_HIGH_PRICE_OFFSET); + this.yearlyLowPrice = buffer.getLong(YEARLY_LOW_PRICE_OFFSET); + } +} diff --git a/src/main/java/com/angelbroking/smartapi/smartstream/models/TokenID.java b/src/main/java/com/angelbroking/smartapi/smartstream/models/TokenID.java new file mode 100644 index 00000000..57463e09 --- /dev/null +++ b/src/main/java/com/angelbroking/smartapi/smartstream/models/TokenID.java @@ -0,0 +1,43 @@ +package com.angelbroking.smartapi.smartstream.models; + +public class TokenID { + + private ExchangeType exchangeType; + private String token; + + public TokenID(ExchangeType exchangeType, String token) throws IllegalArgumentException { + if(exchangeType == null || token == null || token.isEmpty()) { + throw new IllegalArgumentException("Invalid exchangeType or token."); + } + this.exchangeType = exchangeType; + this.token = token; + } + + public ExchangeType getExchangeType() { + return exchangeType; + } + + public String getToken() { + return token; + } + + @Override + public boolean equals(Object obj) { + if(!(obj instanceof TokenID)) { + return false; + } + + TokenID newObj = (TokenID) obj; + return this.exchangeType.equals(newObj.getExchangeType()) && this.token.equals(newObj.getToken()); + } + + @Override + public int hashCode() { + return toString().hashCode(); + } + + @Override + public String toString() { + return (exchangeType.name()+"-"+token); + } +} diff --git a/src/main/java/com/angelbroking/smartapi/smartstream/ticker/SmartStreamListener.java b/src/main/java/com/angelbroking/smartapi/smartstream/ticker/SmartStreamListener.java new file mode 100644 index 00000000..b1875cfe --- /dev/null +++ b/src/main/java/com/angelbroking/smartapi/smartstream/ticker/SmartStreamListener.java @@ -0,0 +1,18 @@ +package com.angelbroking.smartapi.smartstream.ticker; + +import com.angelbroking.smartapi.smartstream.models.*; + +public interface SmartStreamListener { + void onLTPArrival(LTP ltp); + void onQuoteArrival(Quote quote); + void onSnapQuoteArrival(SnapQuote snapQuote); + + void onDepthArrival(Depth depth); + + void onConnected(); + void onDisconnected(); + void onError(SmartStreamError error); + void onPong(); + + SmartStreamError onErrorCustom(); +} \ No newline at end of file diff --git a/src/main/java/com/angelbroking/smartapi/smartstream/ticker/SmartStreamTicker.java b/src/main/java/com/angelbroking/smartapi/smartstream/ticker/SmartStreamTicker.java new file mode 100644 index 00000000..bd873c45 --- /dev/null +++ b/src/main/java/com/angelbroking/smartapi/smartstream/ticker/SmartStreamTicker.java @@ -0,0 +1,387 @@ +package com.angelbroking.smartapi.smartstream.ticker; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.time.LocalDateTime; +import java.util.EnumMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.Timer; +import java.util.TimerTask; + +import com.angelbroking.smartapi.smartstream.models.*; +import com.neovisionaries.ws.client.*; +import org.apache.commons.lang.StringUtils; +import org.json.JSONArray; +import org.json.JSONObject; + +import com.angelbroking.smartapi.Routes; +import com.angelbroking.smartapi.http.exceptions.SmartAPIException; +import com.angelbroking.smartapi.utils.ByteUtils; +import com.angelbroking.smartapi.utils.Utils; + +import lombok.extern.slf4j.Slf4j; + + +@Slf4j +public class SmartStreamTicker { + + private static int pingIntervalInMilliSeconds = 10000; // 10 seconds + + private static int delayInMilliSeconds = 5000; // initial delay in seconds + private static int periodInMilliSeconds = 5000; // initial period in seconds + private static final String clientIdHeader = "x-client-code"; + private static final String feedTokenHeader = "x-feed-token"; + private static final String clientLibHeader = "x-client-lib"; + + private final Routes routes = new Routes(); + private final String wsuri = routes.getSmartStreamWSURI(); + + private final SmartStreamListener smartStreamListener; + private WebSocket ws; + private final String clientId; + private final String feedToken; + private EnumMap> tokensByModeMap = new EnumMap<>(SmartStreamSubsMode.class); + private Timer pingTimer; + private LocalDateTime lastPongReceivedTime = LocalDateTime.now(); + + /** + * Initializes the SmartStreamTicker. + * + * @param clientId - the client ID used for authentication + * @param feedToken - the feed token used for authentication + * @param smartStreamListener - the SmartStreamListener for receiving callbacks + * @throws IllegalArgumentException - if the clientId, feedToken, or SmartStreamListener is null or empty + */ + public SmartStreamTicker(String clientId, String feedToken, SmartStreamListener smartStreamListener) { + if (StringUtils.isEmpty(clientId) || StringUtils.isEmpty(feedToken) || Utils.validateInputNullCheck(smartStreamListener)) { + throw new IllegalArgumentException( + "clientId, feedToken and SmartStreamListener should not be empty or null"); + } + + this.clientId = clientId; + this.feedToken = feedToken; + this.smartStreamListener = smartStreamListener; + init(); + } + + /** + * Initializes the SmartStreamTicker. + * + * @param clientId - the client ID used for authentication + * @param feedToken - the feed token used for authentication + * @param delay - delay in milliseconds + * @param period - period in milliseconds + * @param smartStreamListener - the SmartStreamListener for receiving callbacks + * @throws IllegalArgumentException - if the clientId, feedToken, or SmartStreamListener is null or empty + */ + public SmartStreamTicker(String clientId, String feedToken, SmartStreamListener smartStreamListener, Integer delay, Integer period ) { + if (StringUtils.isEmpty(clientId) || StringUtils.isEmpty(feedToken) || Utils.isEmpty(delay) || Utils.isEmpty(period) || Utils.validateInputNullCheck(smartStreamListener)) { + throw new IllegalArgumentException( + "clientId, feedToken and SmartStreamListener should not be empty or null"); + } + this.delayInMilliSeconds = delay; + this.periodInMilliSeconds = period; + this.clientId = clientId; + this.feedToken = feedToken; + this.smartStreamListener = smartStreamListener; + init(); + } + + + private void init() { + try { + ws = new WebSocketFactory() + .setVerifyHostname(false) + .createSocket(wsuri) + .setPingInterval(pingIntervalInMilliSeconds); + ws.addHeader(clientIdHeader, clientId); + ws.addHeader(feedTokenHeader, feedToken); + ws.addHeader(clientLibHeader, "JAVA"); + ws.addListener(getWebsocketAdapter()); + } catch (IOException e) { + if (Utils.validateInputNotNullCheck(smartStreamListener)) { + smartStreamListener.onError(getErrorHolder(e)); + } + } + } + + + private SmartStreamError getErrorHolder(Throwable e) { + SmartStreamError error = new SmartStreamError(); + error.setException(e); + return error; + } + + /** Returns a WebSocketAdapter to listen to ticker related events. */ + public WebSocketAdapter getWebsocketAdapter() { + return new WebSocketAdapter() { + @Override + public void onConnected(WebSocket websocket, Map> headers) throws WebSocketException { + smartStreamListener.onConnected(); + startPingTimer(websocket); + } + + @Override + public void onTextMessage(WebSocket websocket, String message) throws Exception { + super.onTextMessage(websocket, message); + } + + @Override + public void onBinaryMessage(WebSocket websocket, byte[] binary) { + SmartStreamSubsMode mode = SmartStreamSubsMode.findByVal(binary[0]); + if (Utils.validateInputNullCheck(mode)) { + StringBuilder sb = new StringBuilder(); + sb.append("Invalid SubsMode="); + sb.append(binary[0]); + sb.append(" in the response binary packet"); + smartStreamListener.onError(getErrorHolder(new SmartAPIException(sb.toString()))); + } + try { + switch (mode) { + case LTP: { + ByteBuffer packet = ByteBuffer.wrap(binary).order(ByteOrder.LITTLE_ENDIAN); + LTP ltp = ByteUtils.mapToLTP(packet); + smartStreamListener.onLTPArrival(ltp); + break; + } + case QUOTE: { + ByteBuffer packet = ByteBuffer.wrap(binary).order(ByteOrder.LITTLE_ENDIAN); + Quote quote = ByteUtils.mapToQuote(packet); + smartStreamListener.onQuoteArrival(quote); + break; + } + case SNAP_QUOTE: { + ByteBuffer packet = ByteBuffer.wrap(binary).order(ByteOrder.LITTLE_ENDIAN); + SnapQuote snapQuote = ByteUtils.mapToSnapQuote(packet); + smartStreamListener.onSnapQuoteArrival(snapQuote); + break; + } + case DEPTH_20: { + ByteBuffer packet = ByteBuffer.wrap(binary).order(ByteOrder.LITTLE_ENDIAN); + Depth depth = ByteUtils.mapToDepth20(packet); + smartStreamListener.onDepthArrival(depth); + break; + } + default: { + smartStreamListener.onError(getErrorHolder( + new SmartAPIException("SubsMode=" + mode + " in the response is not handled."))); + break; + } + } + } catch (Exception e) { + smartStreamListener.onError(getErrorHolder(e)); + } + } + + @Override + public void onPongFrame(WebSocket websocket, WebSocketFrame frame) throws Exception { + try { + lastPongReceivedTime = LocalDateTime.now(); + smartStreamListener.onPong(); + } catch (Exception e) { + SmartStreamError error = new SmartStreamError(); + error.setException(e); + smartStreamListener.onError(error); + } + } + + /** + * On disconnection, return statement ensures that the thread ends. + * + * @param websocket + * @param serverCloseFrame + * @param clientCloseFrame + * @param closedByServer + * @throws Exception + */ + @Override + public void onDisconnected(WebSocket websocket, WebSocketFrame serverCloseFrame, + WebSocketFrame clientCloseFrame, boolean closedByServer) { + try { + if (closedByServer) { + reconnectAndResubscribe(); + } else { + stopPingTimer(); + smartStreamListener.onDisconnected(); + } + } catch (Exception e) { + SmartStreamError error = new SmartStreamError(); + error.setException(e); + smartStreamListener.onError(error); + } + } + + @Override + public void onCloseFrame(WebSocket websocket, WebSocketFrame frame) throws Exception { + super.onCloseFrame(websocket, frame); + } + + @Override + public void onError(WebSocket websocket, WebSocketException cause) throws Exception { + smartStreamListener.onErrorCustom(); + } + }; + } + + private void startPingTimer(final WebSocket websocket) { + + pingTimer = new Timer(); + pingTimer.scheduleAtFixedRate(new TimerTask() { + @Override + public void run() { + try { + LocalDateTime currentTime = LocalDateTime.now(); + if (lastPongReceivedTime.isBefore(currentTime.minusSeconds(20))) { + websocket.disconnect(); + reconnectAndResubscribe(); + } + } catch (Exception e) { + smartStreamListener.onError(getErrorHolder(e)); + } + } + }, delayInMilliSeconds, periodInMilliSeconds); // run at every 5 second + } + + private void stopPingTimer() { + if (Utils.validateInputNotNullCheck(pingTimer)) { + pingTimer.cancel(); + pingTimer = null; + } + } + + private void reconnectAndResubscribe() throws WebSocketException { + log.info("reconnectAndResubscribe - started"); + init(); + connect(); + // resubscribing the existing tokens as per the mode + tokensByModeMap.forEach((mode,tokens) -> { + subscribe(mode, tokens); + }); + log.info("reconnectAndResubscribe - done"); + } + + /** Disconnects websocket connection. */ + public void disconnect() { + + if (ws != null) { + stopPingTimer(); + ws.disconnect(); + } + } + + /** + * Returns true if websocket connection is open. + * + * @return boolean + */ + public boolean isConnectionOpen() { + return (ws != null) && ws.isOpen(); + } + + /** + * Returns true if websocket connection is closed. + * + * @return boolean + */ + public boolean isConnectionClosed() { + return !isConnectionOpen(); + } + + /** + * Subscribes tokens. + */ + public void subscribe(SmartStreamSubsMode mode, Set tokens) { + if (ws != null) { + if (ws.isOpen()) { + for (TokenID token : tokens) { + if (ExchangeType.NSE_CM.equals(token.getExchangeType()) && SmartStreamSubsMode.DEPTH_20.equals(mode)) { + if (tokens.size() < 50) { + JSONObject wsMWJSONRequest = getApiRequest(SmartStreamAction.SUBS, mode, tokens); + ws.sendText(wsMWJSONRequest.toString()); + tokensByModeMap.put(mode, tokens); + } else { + smartStreamListener.onError(getErrorHolder(new SmartAPIException("Token size should be less than 50", "504"))); + } + } else { + if (!ExchangeType.NSE_CM.equals(token.getExchangeType()) && SmartStreamSubsMode.DEPTH_20.equals(mode)) { + smartStreamListener.onError(getErrorHolder(new SmartAPIException("Invalid Exchange Type: Please check the exchange type and try again", "504"))); + } else { + JSONObject wsMWJSONRequest = getApiRequest(SmartStreamAction.SUBS, mode, tokens); + ws.sendText(wsMWJSONRequest.toString()); + tokensByModeMap.put(mode, tokens); + } + } + } + } else { + smartStreamListener.onError(getErrorHolder(new SmartAPIException("ticker is not connected", "504"))); + } + } else { + smartStreamListener.onError(getErrorHolder(new SmartAPIException("ticker is null not connected", "504"))); + } + } + + /** + * Unsubscribes tokens. + */ + public void unsubscribe(SmartStreamSubsMode mode, Set tokens) { + if (ws != null) { + if (ws.isOpen()) { + JSONObject wsMWJSONRequest = getApiRequest(SmartStreamAction.UNSUBS, mode, tokens); + ws.sendText(wsMWJSONRequest.toString()); + Set currentlySubscribedTokens = tokensByModeMap.get(mode); + if(currentlySubscribedTokens != null) { + currentlySubscribedTokens.removeAll(tokens); + } + } else { + smartStreamListener.onError(getErrorHolder(new SmartAPIException("ticker is not connected", "504"))); + } + } else { + smartStreamListener.onError(getErrorHolder(new SmartAPIException("ticker is null not connected", "504"))); + } + } + + private JSONArray generateExchangeTokensList(Set tokens) { + Map tokensByExchange = new EnumMap<>(ExchangeType.class); + tokens.stream().forEach(t -> { + JSONArray tokenList = tokensByExchange.get(t.getExchangeType()); + if (tokenList == null) { + tokenList = new JSONArray(); + tokensByExchange.put(t.getExchangeType(), tokenList); + } + + tokenList.put(t.getToken()); + }); + + JSONArray exchangeTokenList = new JSONArray(); + tokensByExchange.forEach((ex, t) -> { + JSONObject exchangeTokenObj = new JSONObject(); + exchangeTokenObj.put("exchangeType", ex.getVal()); + exchangeTokenObj.put("tokens", t); + + exchangeTokenList.put(exchangeTokenObj); + }); + + return exchangeTokenList; + } + + private JSONObject getApiRequest(SmartStreamAction action, SmartStreamSubsMode mode, Set tokens) { + JSONObject params = new JSONObject(); + params.put("mode", mode.getVal()); + params.put("tokenList", this.generateExchangeTokensList(tokens)); + + JSONObject wsMWJSONRequest = new JSONObject(); + wsMWJSONRequest.put("action", action.getVal()); + wsMWJSONRequest.put("params", params); + + return wsMWJSONRequest; + } + + public void connect() throws WebSocketException { + ws.connect(); + log.info("connected to uri: {}", wsuri); + } + +} diff --git a/src/main/java/com/angelbroking/smartapi/utils/ByteUtils.java b/src/main/java/com/angelbroking/smartapi/utils/ByteUtils.java new file mode 100644 index 00000000..208115cd --- /dev/null +++ b/src/main/java/com/angelbroking/smartapi/utils/ByteUtils.java @@ -0,0 +1,95 @@ +package com.angelbroking.smartapi.utils; + +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; + +import com.angelbroking.smartapi.smartstream.models.*; + +import static com.angelbroking.smartapi.utils.Constants.*; + +public class ByteUtils { + + private static final int CHAR_ARRAY_SIZE = 25; + + private ByteUtils() { + + } + + public static LTP mapToLTP(ByteBuffer packet) { + return new LTP(packet); + } + + public static Quote mapToQuote(ByteBuffer packet) { + return new Quote(packet); + } + + public static SnapQuote mapToSnapQuote(ByteBuffer packet) { + return new SnapQuote(packet); + } + public static Depth mapToDepth20(ByteBuffer packet) { + return new Depth(packet); + } + public static TokenID getTokenID(ByteBuffer byteBuffer) { + byte[] token = new byte[CHAR_ARRAY_SIZE]; + for (int i = 0; i < CHAR_ARRAY_SIZE; i++) { + token[i] = byteBuffer.get(2 + i); + } + return new TokenID(ExchangeType.findByValue(byteBuffer.get(1)), new String(token, StandardCharsets.UTF_8)); + } + + public static SmartApiBBSInfo[] getBestFiveBuyData(ByteBuffer buffer) { + SmartApiBBSInfo[] bestFiveBuyData = new SmartApiBBSInfo[NUM_PACKETS]; + + for (int i = 0; i < NUM_PACKETS; i++) { + int offset = BUY_START_POSITION + (i * PACKET_SIZE); + short buySellFlag = buffer.getShort(offset + BUY_SELL_FLAG_OFFSET); + long quantity = buffer.getLong(offset + QUANTITY_OFFSET); + long price = buffer.getLong(offset + PRICE_OFFSET); + short numberOfOrders = buffer.getShort(offset + NUMBER_OF_ORDERS_OFFSET); + bestFiveBuyData[i] = new SmartApiBBSInfo(buySellFlag, quantity, price, numberOfOrders); + } + + return bestFiveBuyData; + } + + public static SmartApiBBSInfo[] getBestFiveSellData(ByteBuffer buffer) { + SmartApiBBSInfo[] bestFiveSellData = new SmartApiBBSInfo[NUM_PACKETS]; + for (int i = 0; i < NUM_PACKETS; i++) { + int offset = SELL_START_POSITION + (i * PACKET_SIZE); + short buySellFlag = buffer.getShort(offset + BUY_SELL_FLAG_OFFSET); + long quantity = buffer.getLong(offset + QUANTITY_OFFSET); + long price = buffer.getLong(offset + PRICE_OFFSET); + short numberOfOrders = buffer.getShort(offset + NUMBER_OF_ORDERS_OFFSET); + bestFiveSellData[i] = new SmartApiBBSInfo(buySellFlag, quantity, price, numberOfOrders); + } + return bestFiveSellData; + } + + public static BestTwentyData[] getBestTwentyBuyData(ByteBuffer buffer) { + BestTwentyData[] bestTwentyBuyData = new BestTwentyData[NUM_PACKETS_FOR_DEPTH]; + + for (int i = 0; i < NUM_PACKETS_FOR_DEPTH; i++) { + int offset = BEST_TWENTY_BUY_DATA_POSITION + (i * PACKET_SIZE_FOR_DEPTH20); + long quantity = buffer.getInt(offset + QUANTITY_OFFSET_FOR_DEPTH20); + long price = buffer.getInt(offset + PRICE_OFFSET_FOR_DEPTH20); + short numberOfOrders = buffer.getShort(offset + NUMBER_OF_ORDERS_OFFSET_FOR_DEPTH20); + bestTwentyBuyData[i] = new BestTwentyData(quantity, price, numberOfOrders); + } + + return bestTwentyBuyData; + } + + public static BestTwentyData[] getBestTwentySellData(ByteBuffer buffer) { + BestTwentyData[] bestTwentyBuyData = new BestTwentyData[NUM_PACKETS_FOR_DEPTH]; + + for (int i = 0; i < NUM_PACKETS_FOR_DEPTH; i++) { + int offset = BEST_TWENTY_SELL_DATA_POSITION + (i * PACKET_SIZE_FOR_DEPTH20); + long quantity = buffer.getInt(offset + QUANTITY_OFFSET_FOR_DEPTH20); + long price = buffer.getInt(offset + PRICE_OFFSET_FOR_DEPTH20); + short numberOfOrders = buffer.getShort(offset + NUMBER_OF_ORDERS_OFFSET_FOR_DEPTH20); + bestTwentyBuyData[i] = new BestTwentyData(quantity, price, numberOfOrders); + } + + return bestTwentyBuyData; + } +} diff --git a/src/main/java/com/angelbroking/smartapi/utils/Constants.java b/src/main/java/com/angelbroking/smartapi/utils/Constants.java index b9ce75f6..a7b0f9d5 100644 --- a/src/main/java/com/angelbroking/smartapi/utils/Constants.java +++ b/src/main/java/com/angelbroking/smartapi/utils/Constants.java @@ -39,5 +39,72 @@ public class Constants { public static String EXCHANGE_CDS = "CDS"; public static String EXCHANGE_NCDEX = "NCDEX"; public static String EXCHANGE_MCX = "MCX"; + + /** + * LTP QUOTE SNAPQUOTE Constants + */ + + public static final int SEQUENCE_NUMBER_OFFSET = 27; + public static final int EXCHANGE_FEED_TIME_OFFSET = 35; + public static final int LAST_TRADED_PRICE_OFFSET = 43; + public static final int SUBSCRIPTION_MODE = 0; + public static final int EXCHANGE_TYPE = 1; + public static final int LAST_TRADED_QTY_OFFSET = 51; + public static final int AVG_TRADED_PRICE_OFFSET = 59; + public static final int VOLUME_TRADED_TODAY_OFFSET = 67; + public static final int TOTAL_BUY_QTY_OFFSET = 75; + public static final int TOTAL_SELL_QTY_OFFSET = 83; + public static final int OPEN_PRICE_OFFSET = 91; + public static final int HIGH_PRICE_OFFSET = 99; + public static final int LOW_PRICE_OFFSET = 107; + public static final int CLOSE_PRICE_OFFSET = 115; + public static final int LAST_TRADED_TIMESTAMP_OFFSET = 123; + public static final int OPEN_INTEREST_OFFSET = 131; + public static final int OPEN_INTEREST_CHANGE_PERC_OFFSET = 139; + public static final int UPPER_CIRCUIT_OFFSET = 347; + public static final int LOWER_CIRCUIT_OFFSET = 355; + public static final int YEARLY_HIGH_PRICE_OFFSET = 363; + public static final int YEARLY_LOW_PRICE_OFFSET = 371; + + + + public static final int BUY_START_POSITION = 147; + public static final int SELL_START_POSITION = 247; + public static final int NUM_PACKETS = 5; + public static final int PACKET_SIZE = 20; + public static final int BUY_SELL_FLAG_OFFSET = 0; + public static final int QUANTITY_OFFSET = 2; + public static final int PRICE_OFFSET = 10; + public static final int NUMBER_OF_ORDERS_OFFSET = 18; + public static final int PRICE_CONVERSION_FACTOR = 100; + + + public static final String SMART_API_EXCEPTION_ERROR_MSG = "The operation failed to execute because of a SmartAPIException error"; + public static final String IO_EXCEPTION_ERROR_MSG = "The operation failed to execute because of an IO error."; + public static final String JSON_EXCEPTION_ERROR_MSG = "The operation failed to execute because of a JSON error"; + public static final String SMART_API_EXCEPTION_OCCURRED = "SmartAPIException occurred "; + public static final String IO_EXCEPTION_OCCURRED = "IOException occurred "; + public static final String JSON_EXCEPTION_OCCURRED = "JSONException occurred "; + + /** + * Depth Constants + */ + public static final int NUM_PACKETS_FOR_DEPTH = 20; + public static final int PACKET_SIZE_FOR_DEPTH20 = 10; + public static final int EXCHANGE_TIMESTAMP_FOR_DEPTH20 = 27; + public static final int PACKET_RECEIVED_TIME_FOR_DEPTH20 = 35; + public static final int BEST_TWENTY_BUY_DATA_POSITION = 43; + public static final int BEST_TWENTY_SELL_DATA_POSITION = 243; + public static final int QUANTITY_OFFSET_FOR_DEPTH20 = 0; + public static final int PRICE_OFFSET_FOR_DEPTH20 = 4; + public static final int NUMBER_OF_ORDERS_OFFSET_FOR_DEPTH20 = 8; + public static final String TOKEN_EXCEPTION_MESSAGE = "Unauthorized access. Please provide a valid or non-expired jwtToken."; + public static final String APIKEY_EXCEPTION_MESSAGE = "Invalid or missing api key. Please provide a valid api key."; + + /** Margin data */ + + public static final String TRADETYPE_BUY = "BUY"; + + public static final String TRADETYPE_SELL = "SELL"; } diff --git a/src/main/java/com/angelbroking/smartapi/utils/Utils.java b/src/main/java/com/angelbroking/smartapi/utils/Utils.java new file mode 100644 index 00000000..2f8eaffc --- /dev/null +++ b/src/main/java/com/angelbroking/smartapi/utils/Utils.java @@ -0,0 +1,58 @@ +package com.angelbroking.smartapi.utils; + +import org.json.JSONObject; + +public class Utils { + private Utils() { + + } + + public static boolean isEmpty(final Integer nm) { + return nm == null || nm.equals(0); + } + + public static boolean areCharArraysEqual(char[] a, char[] b) { + if (a == null && b == null) { + return true; + } + + if (a != null && b != null) { + if (a.length == b.length) { + for (int i = 0; i < a.length; i++) { + if (a[i] != b[i]) { + return false; + } + } + return true; + } + } + return false; + } + + public static boolean areByteArraysEqual(byte[] a, byte[] b) { + if (a == null && b == null) { + return true; + } + + if (a != null && b != null) { + if (a.length == b.length) { + for (int i = 0; i < a.length; i++) { + if (a[i] != b[i]) { + return false; + } + } + return true; + } + } + return false; + } + + public static boolean validateInputNullCheck(T input) { + return input == null; + } + + public static boolean validateInputNotNullCheck(T input) { + return input != null; + } + +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties new file mode 100644 index 00000000..0b47fc16 --- /dev/null +++ b/src/main/resources/application.properties @@ -0,0 +1 @@ +logging.config=classpath:logback.xml \ No newline at end of file diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml new file mode 100644 index 00000000..f43cad99 --- /dev/null +++ b/src/main/resources/logback.xml @@ -0,0 +1,29 @@ + + + + error.log + + %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + INFO + DENY + ACCEPT + + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + + + + + diff --git a/src/test/java/com/angelbroking/smartapi/SmartConnectTest.java b/src/test/java/com/angelbroking/smartapi/SmartConnectTest.java new file mode 100644 index 00000000..f6d70023 --- /dev/null +++ b/src/test/java/com/angelbroking/smartapi/SmartConnectTest.java @@ -0,0 +1,1184 @@ +package com.angelbroking.smartapi; + +import com.angelbroking.smartapi.http.SmartAPIRequestHandler; +import com.angelbroking.smartapi.http.exceptions.DataException; +import com.angelbroking.smartapi.http.exceptions.SmartAPIException; +import com.angelbroking.smartapi.models.*; +import com.angelbroking.smartapi.utils.Constants; +import com.github.tomakehurst.wiremock.common.Json; +import lombok.extern.slf4j.Slf4j; +import org.json.JSONArray; +import org.json.JSONException; + +import org.json.JSONObject; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + + +import static com.angelbroking.smartapi.utils.Constants.IO_EXCEPTION_ERROR_MSG; +import static com.angelbroking.smartapi.utils.Constants.IO_EXCEPTION_OCCURRED; +import static com.angelbroking.smartapi.utils.Constants.JSON_EXCEPTION_ERROR_MSG; +import static com.angelbroking.smartapi.utils.Constants.JSON_EXCEPTION_OCCURRED; +import static com.angelbroking.smartapi.utils.Constants.SMART_API_EXCEPTION_ERROR_MSG; +import static com.angelbroking.smartapi.utils.Constants.SMART_API_EXCEPTION_OCCURRED; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.when; + + +@RunWith(MockitoJUnitRunner.Silent.class) +@Slf4j +public class SmartConnectTest { + @Mock + private SmartAPIRequestHandler smartAPIRequestHandler; + + @Mock + private SmartConnect smartConnect; + + @Mock + private Routes routes; + private String apiKey; + private String accessToken; + + + @Before + public void setup() { + apiKey = "api_key_test"; + accessToken = "dwkdwodmi"; + } + + public JSONObject getErrorResponse(){ + JSONObject errorResponse = new JSONObject(); + errorResponse.put("status",false); + errorResponse.put("message","error_message"); + errorResponse.put("errorcode","AB10011"); + errorResponse.put("data","null"); + + return errorResponse; + } + + @Test + public void generateSession() throws SmartAPIException, IOException { + User user = new User(); + user.setAccessToken("dummyToken"); + user.setRefreshToken("dummyRefreshToken"); + user.setFeedToken("dummyfeedtoken"); + user.setUserId("user001"); + when(smartConnect.generateSession("user001","1100","123321")).thenReturn(user); + + User userData = smartConnect.generateSession("user001","1100","123321"); + assertNotNull(userData); + } + + @Test(expected = SmartAPIException.class) + public void generate_session_exception() throws SmartAPIException, IOException { + String url = routes.getLoginUrl(); + JSONObject params = new JSONObject(); + params.put("clientcode", "user001"); + params.put("password", "1100"); + params.put("totp", "123321"); + when(smartAPIRequestHandler.postRequest(this.apiKey, url, params)) + .thenThrow(new SmartAPIException("Generate Session API request failed")); + try { + JSONObject response = smartAPIRequestHandler.postRequest(apiKey, url, params); + response.getJSONObject("data"); + } catch (SmartAPIException ex) { + throw new SmartAPIException(String.format("%s in generate session %s", SMART_API_EXCEPTION_ERROR_MSG, ex)); + } + } + + @Test + public void getProfile() throws SmartAPIException, IOException { + User user = new User(); + user.setUserId("user001"); + user.setUserName("user_name"); + user.setEmail("usermail@mail.com"); + user.setMobileNo("987176688"); + when(smartConnect.getProfile()).thenReturn(user); + + User userData = smartConnect.getProfile(); + assertNotNull(userData); + } + + @Test(expected = SmartAPIException.class) + public void get_profile_exception() throws SmartAPIException, IOException { + String url = routes.get("api.user.profile"); + when(smartAPIRequestHandler.getRequest(this.apiKey, url, accessToken)) + .thenThrow(new SmartAPIException("Get Profile API Request Failed")); + try { + JSONObject response = smartAPIRequestHandler.getRequest(apiKey, url, accessToken); + response.getJSONObject("data"); + } catch (SmartAPIException ex) { + throw new SmartAPIException(String.format("%s in generate session %s", SMART_API_EXCEPTION_ERROR_MSG, ex)); + } + } + + @Test + public void placeOrder() throws SmartAPIException, IOException { + + OrderParams orderParams = new OrderParams(); + orderParams.variety = Constants.VARIETY_STOPLOSS; + orderParams.quantity = 1; + orderParams.symboltoken = "1660"; + orderParams.exchange = Constants.EXCHANGE_NSE; + orderParams.ordertype = Constants.ORDER_TYPE_STOPLOSS_LIMIT; + orderParams.tradingsymbol = "ITC-EQ"; + orderParams.producttype = Constants.PRODUCT_INTRADAY; + orderParams.duration = Constants.DURATION_DAY; + orderParams.transactiontype = Constants.TRANSACTION_TYPE_BUY; + orderParams.price = 122.2; + orderParams.triggerprice = "209"; + + Order orderResponse = new Order(); + orderResponse.orderId = "generated_orderid"; + + when(smartConnect.placeOrder(orderParams,"STOPLOSS")).thenReturn(orderResponse); + + Order placeOrder = smartConnect.placeOrder(orderParams,"STOPLOSS"); + assertNotNull(placeOrder); + } + + @Test(expected = SmartAPIException.class) + public void place_order_exception() throws SmartAPIException, IOException { + String url = routes.get("api.order.place"); + OrderParams orderParams = new OrderParams(); + orderParams.variety = Constants.VARIETY_STOPLOSS; + orderParams.quantity = 1; + orderParams.symboltoken = "1660"; + orderParams.exchange = Constants.EXCHANGE_NSE; + orderParams.ordertype = Constants.ORDER_TYPE_STOPLOSS_LIMIT; + orderParams.tradingsymbol = "ITC-EQ"; + orderParams.producttype = Constants.PRODUCT_INTRADAY; + orderParams.duration = Constants.DURATION_DAY; + orderParams.transactiontype = Constants.TRANSACTION_TYPE_BUY; + orderParams.price = 122.2; + orderParams.triggerprice = "209"; + + JSONObject params = new JSONObject(); + if (orderParams.exchange != null) + params.put("exchange", orderParams.exchange); + if (orderParams.tradingsymbol != null) + params.put("tradingsymbol", orderParams.tradingsymbol); + if (orderParams.transactiontype != null) + params.put("transactiontype", orderParams.transactiontype); + if (orderParams.quantity != null) + params.put("quantity", orderParams.quantity); + if (orderParams.price != null) + params.put("price", orderParams.price); + if (orderParams.producttype != null) + params.put("producttype", orderParams.producttype); + if (orderParams.ordertype != null) + params.put("ordertype", orderParams.ordertype); + if (orderParams.duration != null) + params.put("duration", orderParams.duration); + if (orderParams.price != null) + params.put("price", orderParams.price); + if (orderParams.symboltoken != null) + params.put("symboltoken", orderParams.symboltoken); + if (orderParams.squareoff != null) + params.put("squareoff", orderParams.squareoff); + if (orderParams.stoploss != null) + params.put("stoploss", orderParams.stoploss); + if (orderParams.triggerprice != null) + params.put("triggerprice", orderParams.triggerprice); + + when(smartAPIRequestHandler.postRequest(this.apiKey, url, params,accessToken)) + .thenThrow(new SmartAPIException("Place order API request failed")); + try { + JSONObject response = smartAPIRequestHandler.postRequest(apiKey, url, params,accessToken); + response.getJSONObject("data"); + } catch (SmartAPIException ex) { + throw new SmartAPIException(String.format("%s in place order %s", SMART_API_EXCEPTION_ERROR_MSG, ex)); + } + } + + @Test + public void modifyOrder() throws SmartAPIException,IOException { + OrderParams orderParams = new OrderParams(); + orderParams.quantity = 1; + orderParams.ordertype = Constants.ORDER_TYPE_LIMIT; + orderParams.tradingsymbol = "ASHOKLEY"; + orderParams.symboltoken = "3045"; + orderParams.producttype = Constants.PRODUCT_DELIVERY; + orderParams.exchange = Constants.EXCHANGE_NSE; + orderParams.duration = Constants.DURATION_DAY; + orderParams.price = 122.2; + + Order orderResponse = new Order(); + orderResponse.orderId = "generated_orderid"; + + when(smartConnect.modifyOrder(orderResponse.orderId,orderParams, orderParams.variety)).thenReturn(orderResponse); + + Order modifyOrder = smartConnect.modifyOrder(orderResponse.orderId,orderParams, orderParams.variety); + assertNotNull(modifyOrder); + } + + @Test + public void cancelOrder() throws SmartAPIException,IOException { + + Order orderResponse = new Order(); + orderResponse.orderId = "generated_orderid"; + + when(smartConnect.cancelOrder(orderResponse.orderId,Constants.VARIETY_NORMAL)).thenReturn(orderResponse); + + Order cancelOrder = smartConnect.cancelOrder(orderResponse.orderId,Constants.VARIETY_NORMAL); + assertNotNull(cancelOrder); + } + + @Test + public void getOrderHistory() throws SmartAPIException,IOException { + + JSONObject response = new JSONObject(); + response.put("status",true); + response.put("message","success"); + + when(smartConnect.getOrderHistory("user001")).thenReturn(response); + + JSONObject orderHistory = smartConnect.getOrderHistory("user001"); + assertNotNull(orderHistory); + Boolean status = orderHistory.getBoolean("status"); + if(!status){ + assertEquals("AB10011",orderHistory.getString("errorcode")); + } + } + + @Test + public void getLTP() throws SmartAPIException,IOException { + + JSONObject response = new JSONObject(); + response.put("status",true); + response.put("message","success"); + JSONObject data = new JSONObject(); + data.put("exchange","NSE"); + data.put("tradingsymbol","SBIN-EQ"); + data.put("symboltoken","3045"); + data.put("open","186"); + data.put("high","191.25"); + data.put("low", "185"); + data.put("ltp","191"); + + response.put("data",data); + + when(smartConnect.getLTP("NSE","SBIN-EQ","3045")).thenReturn(response); + + JSONObject ltpData = smartConnect.getLTP("NSE","SBIN-EQ","3045"); + assertNotNull(ltpData); + Boolean status = ltpData.getBoolean("status"); + if(!status){ + assertEquals("AB10011",ltpData.getString("errorcode")); + } + } + + @Test + public void getTrades() throws SmartAPIException,IOException { + + JSONObject response = new JSONObject(); + response.put("status",true); + response.put("message","success"); + + when(smartConnect.getTrades()).thenReturn(response); + + JSONObject tradebook = smartConnect.getTrades(); + assertNotNull(tradebook); + Boolean status = tradebook.getBoolean("status"); + if(!status){ + assertEquals("AB10011",tradebook.getString("errorcode")); + } + } + + @Test + public void getRMS() throws SmartAPIException,IOException { + + JSONObject response = new JSONObject(); + response.put("status",true); + response.put("message","success"); + JSONObject data = new JSONObject(); + data.put("net","9999999999999"); + data.put("availablecash","9999999999999"); + data.put("availableintradaypayin","0"); + data.put("availablelimitmargin","0"); + data.put("collateral","0"); + data.put("m2munrealized", "0"); + data.put("utilisedpayout","0"); + + response.put("data",data); + + when(smartConnect.getRMS()).thenReturn(response); + + JSONObject rms = smartConnect.getRMS(); + assertNotNull(rms); + Boolean status = rms.getBoolean("status"); + if(!status){ + assertEquals("AB10011",rms.getString("errorcode")); + } + } + + @Test + public void getHolding() throws SmartAPIException,IOException { + + JSONObject response = new JSONObject(); + response.put("status",true); + response.put("message","success"); + JSONObject data = new JSONObject(); + data.put("tradingsymbol","TATASTEEL-EQ"); + data.put("exchange","NSE"); + data.put("isin","INE081A01020"); + data.put("t1quantity","0"); + data.put("realisedquantity","2"); + data.put("quantity", "2"); + data.put("product","DELIVERY"); + data.put("authorisedquantity","0"); + data.put("collateralquantity","null"); + data.put("collateraltype","null"); + data.put("haircut","0"); + data.put("averageprice","111.87"); + data.put("ltp","111.87"); + data.put("symboltoken","3499"); + data.put("close","129.6"); + data.put("profitandloss","37"); + data.put("pnlpercentage","16.34"); + + response.put("data",data); + + when(smartConnect.getHolding()).thenReturn(response); + + JSONObject holdings = smartConnect.getHolding(); + assertNotNull(holdings); + Boolean status = holdings.getBoolean("status"); + if(!status){ + assertEquals("AB10011",holdings.getString("errorcode")); + } + } + + @Test + public void getAllHolding() throws SmartAPIException,IOException { + + JSONObject response = new JSONObject(); + response.put("status",true); + response.put("message","success"); + JSONObject data = new JSONObject(); + JSONObject totalholding = new JSONObject(); + totalholding.put("totalholdingvalue","5294"); + totalholding.put("totalinvvalue","5116"); + totalholding.put("totalprofitandloss","178.14"); + totalholding.put("totalpnlpercentage","3.48"); + + data.put("totalholding",totalholding); + JSONObject holding = new JSONObject(); + holding.put("tradingsymbol","TATASTEEL-EQ"); + holding.put("exchange","NSE"); + holding.put("isin","INE081A01020"); + holding.put("t1quantity","0"); + holding.put("realisedquantity","2"); + holding.put("quantity", "2"); + holding.put("product","DELIVERY"); + holding.put("authorisedquantity","0"); + holding.put("collateralquantity","null"); + holding.put("collateraltype","null"); + holding.put("haircut","0"); + holding.put("averageprice","111.87"); + holding.put("ltp","111.87"); + holding.put("symboltoken","3499"); + holding.put("close","129.6"); + holding.put("profitandloss","37"); + holding.put("pnlpercentage","16.34"); + + JSONArray holdings = new JSONArray(); + holdings.put(holding); + data.put("holdings",holdings); + response.put("data",data); + + when(smartConnect.getAllHolding()).thenReturn(response); + + JSONObject allHoldings = smartConnect.getAllHolding(); + assertNotNull(allHoldings); + Boolean status = allHoldings.getBoolean("status"); + if(!status){ + assertEquals("AB10011",allHoldings.getString("errorcode")); + } + } + + @Test + public void getPosition() throws SmartAPIException,IOException { + + JSONObject response = new JSONObject(); + response.put("status",true); + response.put("message","success"); + + JSONObject position = new JSONObject(); + position.put("tradingsymbol","TATASTEEL-EQ"); + position.put("exchange","NSE"); + position.put("instrumenttype",""); + position.put("t1quantity","0"); + position.put("realisedquantity","2"); + position.put("quantity", "2"); + position.put("product","DELIVERY"); + position.put("authorisedquantity","0"); + position.put("collateralquantity","null"); + position.put("collateraltype","null"); + position.put("haircut","0"); + position.put("averageprice","111.87"); + position.put("ltp","111.87"); + position.put("symboltoken","3499"); + position.put("close","129.6"); + position.put("totalbuyavgprice","37"); + position.put("totalsellavgprice","16.34"); + + JSONArray positions = new JSONArray(); + positions.put(position); + response.put("data",positions); + + when(smartConnect.getPosition()).thenReturn(response); + + JSONObject positionData = smartConnect.getPosition(); + assertNotNull(positionData); + } + + @Test + public void convertPosition() throws SmartAPIException, IOException{ + + JSONObject requestObejct = new JSONObject(); + requestObejct.put("exchange", "NSE"); + requestObejct.put("oldproducttype", "DELIVERY"); + requestObejct.put("newproducttype", "MARGIN"); + requestObejct.put("tradingsymbol", "SBIN-EQ"); + requestObejct.put("transactiontype", "BUY"); + requestObejct.put("quantity", 1); + requestObejct.put("type", "DAY"); + + JSONObject response = new JSONObject(); + response.put("status",true); + response.put("message","success"); + response.put("errorcode",""); + response.put("data","null"); + + when(smartConnect.convertPosition(requestObejct)).thenReturn(response); + + JSONObject convertPosition = smartConnect.convertPosition(requestObejct); + assertNotNull(convertPosition); + } + + @Test + public void gttCreateRule() throws SmartAPIException,IOException { + GttParams gttParams = new GttParams(); + + gttParams.tradingsymbol = "SBIN-EQ"; + gttParams.symboltoken = "3045"; + gttParams.exchange = "NSE"; + gttParams.producttype = "MARGIN"; + gttParams.transactiontype = "BUY"; + gttParams.price = 100000.01; + gttParams.qty = 10; + gttParams.disclosedqty = 10; + gttParams.triggerprice = 20000.1; + gttParams.timeperiod = 300; + + Gtt response = new Gtt(); + + when(smartConnect.gttCreateRule(gttParams)).thenReturn(response); + + Gtt gttData = smartConnect.gttCreateRule(gttParams); + assertNotNull(gttData); + } + + @Test + public void gttModifyRule() throws SmartAPIException,IOException { + GttParams gttParams = new GttParams(); + + gttParams.tradingsymbol = "SBIN-EQ"; + gttParams.symboltoken = "3045"; + gttParams.exchange = "NSE"; + gttParams.producttype = "MARGIN"; + gttParams.transactiontype = "BUY"; + gttParams.price = 100000.1; + gttParams.qty = 10; + gttParams.disclosedqty = 10; + gttParams.triggerprice = 20000.1; + gttParams.timeperiod = 300; + + Integer id = 1000051; + Gtt response = new Gtt(); + + when(smartConnect.gttModifyRule(id,gttParams)).thenReturn(response); + + Gtt gttData = smartConnect.gttModifyRule(id,gttParams); + assertNotNull(gttData); + } + + @Test + public void gttCancelRule() throws SmartAPIException,IOException { + + Integer id = 1000051; + String token = "3045"; + String exchange = "NSE"; + + Gtt response = new Gtt(); + + when(smartConnect.gttCancelRule(id,token,exchange)).thenReturn(response); + + Gtt gttData = smartConnect.gttCancelRule(id,token,exchange); + assertNotNull(gttData); + } + + @Test + public void gttRuleDetails() throws SmartAPIException,IOException { + + Integer id = 1000051; + + JSONObject response = new JSONObject(); + response.put("status",true); + response.put("message","success"); + response.put("errorcode",""); + JSONObject data = new JSONObject(); + data.put("status","NEW"); + data.put("createddate","2020-11-16T14:19:51Z"); + data.put("updateddate","2020-11-16T14:28:01Z"); + data.put("expirydate","2021-11-16T14:19:51Z"); + data.put("clientid","100"); + data.put("tradingsymbol","SBIN-EQ"); + data.put("symboltoken","3045"); + data.put("exchange","NSE"); + data.put("transactiontype","BUY"); + data.put("producttype","DELIVERY"); + data.put("price","195"); + data.put("qty","1"); + data.put("triggerprice","196"); + data.put("disclosedqty","10"); + response.put("data",data); + + when(smartConnect.gttRuleDetails(id)).thenReturn(response); + + JSONObject gttData = smartConnect.gttRuleDetails(id); + assertNotNull(gttData); + } + + @Test + public void gttRuleList() throws SmartAPIException,IOException { + + List status = new ArrayList() { + { + add("NEW"); + add("CANCELLED"); + add("ACTIVE"); + add("SENTTOEXCHANGE"); + add("FORALL"); + } + }; + Integer page = 1; + Integer count = 10; + + JSONObject gtt = new JSONObject(); + gtt.put("status","NEW"); + gtt.put("createddate","2020-11-16T14:19:51Z"); + gtt.put("updateddate","2020-11-16T14:28:01Z"); + gtt.put("expirydate","2021-11-16T14:19:51Z"); + gtt.put("clientid","100"); + gtt.put("tradingsymbol","SBIN-EQ"); + gtt.put("symboltoken","3045"); + gtt.put("exchange","NSE"); + gtt.put("transactiontype","BUY"); + gtt.put("producttype","DELIVERY"); + gtt.put("price","195"); + gtt.put("qty","1"); + gtt.put("triggerprice","196"); + gtt.put("disclosedqty","10"); + JSONArray data = new JSONArray(); + data.put(gtt); + + when(smartConnect.gttRuleList(status, page,count)).thenReturn(data); + + JSONArray gttData = smartConnect.gttRuleList(status, page,count); + assertNotNull(gttData); + } + + @Test + public void candleData() throws SmartAPIException,IOException { + + JSONObject requestObejct = new JSONObject(); + requestObejct.put("exchange", "NSE"); + requestObejct.put("symboltoken", "3045"); + requestObejct.put("interval", "ONE_MINUTE"); + requestObejct.put("fromdate", "2021-03-08 09:00"); + requestObejct.put("todate", "2021-03-09 09:20"); + + JSONObject response = new JSONObject(); + response.put("status",true); + response.put("message","success"); + response.put("errorcode",""); + JSONArray candleData = new JSONArray(); + candleData.put("2023-09-06T11:15:00+05:30"); + candleData.put("19571.2"); + candleData.put("19571.34"); + response.put("data",candleData); + + when(smartConnect.candleData(requestObejct)).thenReturn(candleData); + + JSONArray candleDatas = smartConnect.candleData(requestObejct); + assertNotNull(candleDatas); + } + + @Test + public void logout() throws SmartAPIException, IOException { + JSONObject response = new JSONObject(); + response.put("status",true); + response.put("message","success"); + response.put("errorcode",""); + response.put("data",""); + + when(smartConnect.logout()).thenReturn(response); + JSONObject user = smartConnect.logout(); + assertNotNull(user); + } + + @Test + public void estimateCharges() throws SmartAPIException, IOException { + List estimateChargesParamsList = new ArrayList<>(); + EstimateChargesParams estimate_Charges_Params = new EstimateChargesParams(); + estimate_Charges_Params.product_type = Constants.PRODUCT_DELIVERY; + estimate_Charges_Params.transaction_type = Constants.TRANSACTION_TYPE_BUY; + estimate_Charges_Params.quantity = "10"; + estimate_Charges_Params.price = "800"; + estimate_Charges_Params.exchange = Constants.EXCHANGE_NSE; + estimate_Charges_Params.symbol_name = "745AS33"; + estimate_Charges_Params.token = "17117"; + + JSONObject response = new JSONObject(); + response.put("status",true); + response.put("message","success"); + response.put("errorcode",""); + response.put("data",""); + + estimateChargesParamsList.add(estimate_Charges_Params); + when(smartConnect.estimateCharges(estimateChargesParamsList)).thenReturn(response); + JSONObject estimateData = smartConnect.estimateCharges(estimateChargesParamsList); + assertNotNull(estimateData); + } + + @Test + public void verifyDis() throws SmartAPIException, IOException{ + JSONObject payload = new JSONObject(); + payload.put("isin", "INE242A01010"); + payload.put("quantity", "1"); + + JSONObject response = new JSONObject(); + response.put("status",true); + response.put("message","success"); + response.put("errorcode",""); + + JSONObject data = new JSONObject(); + data.put("ReqId","8180722758077144"); + data.put("ReturnURL","https://trade.angelbroking.com/cdslpoa/response"); + data.put("DPId","33200"); + data.put("BOID","1203320015222472"); + data.put("TransDtls","fZ6jlmt9GosSO0kFdI9S9FCD+IYFvjUN94Bph46YMC1BzexE1hDuCwjSUzXVoEgV3mTP5aXnwxJDikFm1xymcjfhEgtWm7ykrpxaDXSuQF25Fg5olDgXy/Suu916VNg9XID0GHy1CT5E9WBP0gocixvOFrCPFmRMmY+7Nqbb3cNfqPZ8uHfX0un5tFnQXV3AXK0g2exwRf3EINSTHSv66/inPArtDko70vuc1pb5e0tRXa14FN2hzklop2UyrcIiDmkmzcHvjdGGomCM4PU90S28xHze5/dAlTv7ywIzrQOA4N2LW7n7M9atFExQTC2tczdwhKkVzScYmpVdRvtY+Lqo8o/OSVQ8Gd3Guz7ZRpqV5073lZ/BnPN8FtJW6shfOwgbYgqmhV2jik0uw57eQ7f+SI0pYYC8noOwKncJ3/umtVY2NVgLjdZq2yxZh7wTQKC2WYaYl/MnZLpgF9yYlBAtZ6trgLG6kcmtlbibtkimi2TecMGN3KrAETsWY07fZCc9Ks/RetFzD1qNIGWZ/4WnpWyW5XTxSxlQILCz7Qwk5f+dKcXVe5CS/7DMB7aa9KQ4t1ru1xo7jM4GmUdwcGVwUqb2pfNSEUX+I10INA0TwXkWdUAAQYO0++q6mYpN59G3IW9vV/dW0/bHh4xcsPg9ysDBZ8bLlk4C3hL6RiVrxcF2AgxjJgLSxL2YerAKkgivk22KULtEDpOpE7IcwxjuWjRxOPGfnSGbc4Ii1avte50WZFh6EKIP6E16sZgKaOh/r5CSnysEtDetvhn8siIWDQbhInAoExMpsuewIthg4QVWvx0EzQL6LqNO74Hc9/JicH+cGFtn6nHjwHgquzbCZx6W6XlzHJVV04Pd0m4kXC27RrnoraFj3KpXcfmdSr0GK3HtUKYV2QgSM8COvEEuL++oxjD4PKi40JmTv2I="); + data.put("version","1.1"); + + response.put("data",data); + when(smartConnect.verifyDis(payload)).thenReturn(response); + + JSONObject verifyDisResponse = smartConnect.verifyDis(payload); + assertNotNull(verifyDisResponse); + } + + @Test + public void generateTPIN() throws SmartAPIException,IOException{ + JSONObject payload = new JSONObject(); + payload.put("dpId", "33200"); + payload.put("ReqId", "1431307824801952"); + payload.put("boid", "1203320018563571"); + payload.put("pan", "JZTPS2255C"); + + JSONObject response = new JSONObject(); + response.put("status",true); + response.put("message","success"); + response.put("errorcode",""); + response.put("data","null"); + + when(smartConnect.generateTPIN(payload)).thenReturn(response); + JSONObject tpinResponse = smartConnect.generateTPIN(payload); + assertNotNull(tpinResponse); + } + + @Test + public void getTranStatus() throws SmartAPIException,IOException{ + JSONObject payload = new JSONObject(); + payload.put("ReqId", "1431307824801952"); + + JSONObject response = new JSONObject(); + response.put("status",true); + response.put("message","success"); + response.put("errorcode",""); + + JSONObject data = new JSONObject(); + data.put("ReqId","8180722758077144"); + data.put("ReqType","D"); + data.put("ResId","1603202259241073"); + data.put("ResStatus","0"); + data.put("ResTime","17032022000022"); + data.put("ResError",""); + data.put("Remarks",""); + + response.put("data",data); + when(smartConnect.getTranStatus(payload)).thenReturn(response); + JSONObject transResponse = smartConnect.getTranStatus(payload); + assertNotNull(transResponse); + } + + @Test + public void optionGreek() throws SmartAPIException,IOException{ + JSONObject payload = new JSONObject(); + payload.put("name", "TCS"); + payload.put("expirydate", "25MAR2024"); + + JSONObject response = new JSONObject(); + response.put("status",true); + response.put("message","success"); + response.put("errorcode",""); + + JSONObject obj = new JSONObject(); + obj.put("name","TCS"); + obj.put("expiry","25JAN2024"); + obj.put("strikePrice","3900.000000"); + obj.put("optionType","CE"); + obj.put("delta","0.492400"); + obj.put("gamma","0.002800"); + obj.put("tradeVolume","24048.00"); + JSONArray data = new JSONArray(); + data.put(data); + response.put("data",data); + + when(smartConnect.optionGreek(payload)).thenReturn(response); + JSONObject optionResponse = smartConnect.optionGreek(payload); + assertNotNull(optionResponse); + } + + @Test + public void gainersLosers() throws SmartAPIException,IOException{ + JSONObject payload = new JSONObject(); + payload.put("datatype", "PercOIGainers"); + payload.put("expirytype", "NEAR"); + + JSONObject response = new JSONObject(); + response.put("status",true); + response.put("message","success"); + response.put("errorcode",""); + + JSONObject obj = new JSONObject(); + obj.put("tradingSymbol","HDFCBANK25JAN24FUT"); + obj.put("percentChange","20.02"); + obj.put("symbolToken","55394"); + obj.put("opnInterest","118861600"); + obj.put("netChangeOpnInterest","1.98253E7"); + JSONArray data = new JSONArray(); + data.put(data); + response.put("data",data); + + when(smartConnect.gainersLosers(payload)).thenReturn(response); + JSONObject gainersLosers = smartConnect.gainersLosers(payload); + assertNotNull(gainersLosers); + } + + @Test + public void putCallRatio() throws SmartAPIException,IOException{ + JSONObject response = new JSONObject(); + response.put("status",true); + response.put("message","success"); + response.put("errorcode",""); + + JSONObject obj = new JSONObject(); + obj.put("pcr",1.04); + obj.put("tradingSymbol","NIFTY25JAN24FUT"); + JSONArray data = new JSONArray(); + data.put(data); + response.put("data",data); + + when(smartConnect.putCallRatio()).thenReturn(response); + JSONObject putCallRatio = smartConnect.putCallRatio(); + assertNotNull(putCallRatio); + } + + @Test + public void oIBuildup() throws SmartAPIException,IOException{ + JSONObject payload = new JSONObject(); + payload.put("expirytype", "NEAR"); + payload.put("datatype", "Long Built Up"); + + JSONObject response = new JSONObject(); + response.put("status",true); + response.put("message","success"); + response.put("errorcode",""); + + JSONObject obj = new JSONObject(); + obj.put("symbolToken",55424); + obj.put("ltp","723.8"); + obj.put("netChange","-28.25"); + obj.put("percentChange","-3.76"); + obj.put("opnInterest","24982.5"); + obj.put("netChangeOpnInterest","76.25"); + obj.put("tradingSymbol","JINDALSTEL25JAN24FUT"); + JSONArray data = new JSONArray(); + data.put(data); + response.put("data",data); + + when(smartConnect.oIBuildup(payload)).thenReturn(response); + JSONObject responseData = smartConnect.oIBuildup(payload); + assertNotNull(responseData); + } + + @Test + public void getSearchScrip() throws SmartAPIException, IOException { + // Mock the necessary objects + JSONObject payload = new JSONObject(); + when(smartConnect.getSearchScrip(payload)).thenReturn("response-data"); + + // Call the method under test + String result = smartConnect.getSearchScrip(payload); + // Assert the result + assertEquals("response-data", result); + + } + + @Test(expected = SmartAPIException.class) + public void testGetSearchScript_Exception() throws SmartAPIException, IOException { + JSONObject payload = new JSONObject(); + SmartAPIException expectedException = new SmartAPIException("Simulated SmartAPIException"); + when(smartConnect.getSearchScrip(payload)).thenThrow(expectedException); + try { + smartConnect.getSearchScrip(payload); + } catch (SmartAPIException e) { + throw new SmartAPIException(String.format("The operation failed to execute because of a SmartAPIException error in Search scrip api data %s", e)); + } + verify(smartConnect).getSearchScrip(payload); + } + + + + + private static JSONObject createMarketDataResponse() { + JSONObject jsonObject = new JSONObject(); + + // Create "data" object + JSONObject dataObject = new JSONObject(); + + // Create the "unfetched" array + JSONArray unfetchedArray = new JSONArray(); + dataObject.put("unfetched", unfetchedArray); + + // Create the "fetched" array and its elements + JSONArray fetchedArray = new JSONArray(); + JSONObject fetchedElement = new JSONObject(); + fetchedElement.put("netChange", 3.15); + fetchedElement.put("tradeVolume", 5718111); + fetchedElement.put("lowerCircuit", 533.15); + fetchedElement.put("percentChange", 0.53); + fetchedElement.put("exchFeedTime", "19-Jul-2023 11:20:51"); + fetchedElement.put("avgPrice", 595.25); + fetchedElement.put("ltp", 595.5); + fetchedElement.put("exchTradeTime", "19-Jul-2023 11:20:51"); + fetchedElement.put("totSellQuan", 1924292); + fetchedElement.put("upperCircuit", 651.55); + fetchedElement.put("lastTradeQty", 46); + fetchedElement.put("high", 599.6); + fetchedElement.put("totBuyQuan", 890300); + + // Create the "depth" object and its "buy" and "sell" arrays + JSONObject depthObject = new JSONObject(); + JSONArray buyArray = new JSONArray(); + JSONArray sellArray = new JSONArray(); + + // Add elements to "buy" array + JSONObject buyElement1 = new JSONObject(); + buyElement1.put("quantity", 1776); + buyElement1.put("price", 595.3); + buyElement1.put("orders", 3); + buyArray.put(buyElement1); + + JSONObject buyElement2 = new JSONObject(); + buyElement2.put("quantity", 767); + buyElement2.put("price", 595.25); + buyElement2.put("orders", 3); + buyArray.put(buyElement2); + + // Add elements to "sell" array + JSONObject sellElement1 = new JSONObject(); + sellElement1.put("quantity", 249); + sellElement1.put("price", 595.5); + sellElement1.put("orders", 5); + sellArray.put(sellElement1); + + JSONObject sellElement2 = new JSONObject(); + sellElement2.put("quantity", 1379); + sellElement2.put("price", 595.55); + sellElement2.put("orders", 4); + sellArray.put(sellElement2); + + // Add "buy" and "sell" arrays to "depth" object + depthObject.put("buy", buyArray); + depthObject.put("sell", sellArray); + + fetchedElement.put("depth", depthObject); + + // Add remaining properties to "fetched" element + fetchedElement.put("low", 592); + fetchedElement.put("exchange", "NSE"); + fetchedElement.put("opnInterest", 0); + fetchedElement.put("tradingSymbol", "SBIN-EQ"); + fetchedElement.put("symbolToken", "3045"); + fetchedElement.put("close", 592.35); + fetchedElement.put("52WeekLow", 482.1); + fetchedElement.put("open", 594.65); + fetchedElement.put("52WeekHigh", 629.55); + + // Add the "fetched" element to the "fetched" array + fetchedArray.put(fetchedElement); + + dataObject.put("fetched", fetchedArray); + + // Add "data" object, "message", "errorcode", and "status" properties to the main JSON object + jsonObject.put("data", dataObject); + jsonObject.put("message", "SUCCESS"); + jsonObject.put("errorcode", ""); + jsonObject.put("status", true); + + return jsonObject; + } + + // Testing market data success for Full payload + @Test + public void marketData() throws SmartAPIException, IOException { + String url = routes.get("api.market.data"); + JSONObject params = getMarketDataRequest("FULL"); + when(smartAPIRequestHandler.postRequest(eq(this.apiKey), eq(url), eq(params), eq(this.accessToken))).thenReturn(createMarketDataResponse()); + try { + JSONObject response = smartAPIRequestHandler.postRequest(this.apiKey, url, params, this.accessToken); + JSONObject data = response.getJSONObject("data"); + assertNotNull(data); + } catch (SmartAPIException ex) { + log.error("{} while placing order {}", SMART_API_EXCEPTION_OCCURRED, ex.toString()); + throw new SmartAPIException(String.format("%s in placing order %s", SMART_API_EXCEPTION_ERROR_MSG, ex)); + } catch (IOException ex) { + log.error("{} while placing order {}", IO_EXCEPTION_OCCURRED, ex.getMessage()); + throw new IOException(String.format("%s in placing order %s", IO_EXCEPTION_ERROR_MSG, ex.getMessage())); + } catch (JSONException ex) { + log.error("{} while placing order {}", JSON_EXCEPTION_OCCURRED, ex.getMessage()); + throw new JSONException(String.format("%s in placing order %s", JSON_EXCEPTION_ERROR_MSG, ex.getMessage())); + } + } + + // Testing market data failure for Full payload + @Test(expected = SmartAPIException.class) + public void testMarketData_Failure() throws SmartAPIException, IOException { + // Stub the postRequest method + String url = routes.get("api.market.data"); + JSONObject params = getMarketDataRequest("FULL"); + when(smartAPIRequestHandler.postRequest(eq(this.apiKey), eq(url), eq(params), eq(this.accessToken))) + .thenThrow(new SmartAPIException("API request failed")); + try { + JSONObject response = smartAPIRequestHandler.postRequest(apiKey, url, params, accessToken); + response.getJSONObject("data"); + } catch (SmartAPIException ex) { + log.error("{} while placing order {}", SMART_API_EXCEPTION_OCCURRED, ex.toString()); + throw new SmartAPIException(String.format("%s in placing order %s", SMART_API_EXCEPTION_ERROR_MSG, ex)); + } catch (IOException ex) { + log.error("{} while placing order {}", IO_EXCEPTION_OCCURRED, ex.getMessage()); + throw new IOException(String.format("%s in placing order %s", IO_EXCEPTION_ERROR_MSG, ex.getMessage())); + } catch (JSONException ex) { + log.error("{} while placing order {}", JSON_EXCEPTION_OCCURRED, ex.getMessage()); + throw new JSONException(String.format("%s in placing order %s", JSON_EXCEPTION_ERROR_MSG, ex.getMessage())); + } + } + + // Testing market data success for LTP payload + @Test + public void testMarketDataLTP_Success() throws SmartAPIException, IOException { + String url = routes.get("api.market.data"); + JSONObject params = getMarketDataRequest("LTP"); + when(smartAPIRequestHandler.postRequest(eq(this.apiKey), eq(url), eq(params), eq(this.accessToken))).thenReturn(createMarketDataResponse()); + try { + JSONObject response = smartAPIRequestHandler.postRequest(this.apiKey, url, params, this.accessToken); + JSONObject data = response.getJSONObject("data"); + assertNotNull(data); + } catch (SmartAPIException ex) { + log.error("{} while placing order {}", SMART_API_EXCEPTION_OCCURRED, ex.toString()); + throw new SmartAPIException(String.format("%s in placing order %s", SMART_API_EXCEPTION_ERROR_MSG, ex)); + } catch (IOException ex) { + log.error("{} while placing order {}", IO_EXCEPTION_OCCURRED, ex.getMessage()); + throw new IOException(String.format("%s in placing order %s", IO_EXCEPTION_ERROR_MSG, ex.getMessage())); + } catch (JSONException ex) { + log.error("{} while placing order {}", JSON_EXCEPTION_OCCURRED, ex.getMessage()); + throw new JSONException(String.format("%s in placing order %s", JSON_EXCEPTION_ERROR_MSG, ex.getMessage())); + } + } + + // Testing market data failure for LTP payload + @Test(expected = SmartAPIException.class) + public void testMarketDataLTP_Failure() throws SmartAPIException, IOException { + // Stub the postRequest method + String url = routes.get("api.market.data"); + JSONObject params = getMarketDataRequest("LTP"); + when(smartAPIRequestHandler.postRequest(eq(this.apiKey), eq(url), eq(params), eq(this.accessToken))) + .thenThrow(new SmartAPIException("API request failed")); + try { + JSONObject response = smartAPIRequestHandler.postRequest(apiKey, url, params, accessToken); + response.getJSONObject("data"); + } catch (SmartAPIException ex) { + log.error("{} while placing order {}", SMART_API_EXCEPTION_OCCURRED, ex.toString()); + throw new SmartAPIException(String.format("%s in placing order %s", SMART_API_EXCEPTION_ERROR_MSG, ex)); + } catch (IOException ex) { + log.error("{} while placing order {}", IO_EXCEPTION_OCCURRED, ex.getMessage()); + throw new IOException(String.format("%s in placing order %s", IO_EXCEPTION_ERROR_MSG, ex.getMessage())); + } catch (JSONException ex) { + log.error("{} while placing order {}", JSON_EXCEPTION_OCCURRED, ex.getMessage()); + throw new JSONException(String.format("%s in placing order %s", JSON_EXCEPTION_ERROR_MSG, ex.getMessage())); + } + } + + // Testing market data success for OHLC payload + @Test + public void testMarketDataOHLC_Success() throws SmartAPIException, IOException { + String url = routes.get("api.market.data"); + JSONObject params = getMarketDataRequest("OHLC"); + when(smartAPIRequestHandler.postRequest(eq(this.apiKey), eq(url), eq(params), eq(this.accessToken))).thenReturn(createMarketDataResponse()); + try { + JSONObject response = smartAPIRequestHandler.postRequest(this.apiKey, url, params, this.accessToken); + JSONObject data = response.getJSONObject("data"); + assertNotNull(data); + } catch (SmartAPIException ex) { + log.error("{} while placing order {}", SMART_API_EXCEPTION_OCCURRED, ex.toString()); + throw new SmartAPIException(String.format("%s in placing order %s", SMART_API_EXCEPTION_ERROR_MSG, ex)); + } catch (IOException ex) { + log.error("{} while placing order {}", IO_EXCEPTION_OCCURRED, ex.getMessage()); + throw new IOException(String.format("%s in placing order %s", IO_EXCEPTION_ERROR_MSG, ex.getMessage())); + } catch (JSONException ex) { + log.error("{} while placing order {}", JSON_EXCEPTION_OCCURRED, ex.getMessage()); + throw new JSONException(String.format("%s in placing order %s", JSON_EXCEPTION_ERROR_MSG, ex.getMessage())); + } + } + + // Testing market data failure for OHLC payload + @Test(expected = SmartAPIException.class) + public void testMarketDataOHLC_Failure() throws SmartAPIException, IOException { + // Stub the postRequest method + String url = routes.get("api.market.data"); + JSONObject params = getMarketDataRequest("OHLC"); + when(smartAPIRequestHandler.postRequest(eq(this.apiKey), eq(url), eq(params), eq(this.accessToken))) + .thenThrow(new SmartAPIException("API request failed")); + try { + JSONObject response = smartAPIRequestHandler.postRequest(apiKey, url, params, accessToken); + response.getJSONObject("data"); + } catch (SmartAPIException ex) { + log.error("{} while placing order {}", SMART_API_EXCEPTION_OCCURRED, ex.toString()); + throw new SmartAPIException(String.format("%s in placing order %s", SMART_API_EXCEPTION_ERROR_MSG, ex)); + } catch (IOException ex) { + log.error("{} while placing order {}", IO_EXCEPTION_OCCURRED, ex.getMessage()); + throw new IOException(String.format("%s in placing order %s", IO_EXCEPTION_ERROR_MSG, ex.getMessage())); + } catch (JSONException ex) { + log.error("{} while placing order {}", JSON_EXCEPTION_OCCURRED, ex.getMessage()); + throw new JSONException(String.format("%s in placing order %s", JSON_EXCEPTION_ERROR_MSG, ex.getMessage())); + } + } + + private JSONObject getMarketDataRequest(String mode) { + JSONObject payload = new JSONObject(); + payload.put("mode", mode); + JSONObject exchangeTokens = new JSONObject(); + JSONArray nseTokens = new JSONArray(); + nseTokens.put("3045"); + exchangeTokens.put("NSE", nseTokens); + payload.put("exchangeTokens", exchangeTokens); + return payload; + } + + public static JSONObject createIndividualOrderResponse() { + JSONObject jsonObject = new JSONObject(); + jsonObject.put("status", true); + jsonObject.put("message", "SUCCESS"); + jsonObject.put("errorcode", ""); + + JSONObject dataObject = new JSONObject(); + dataObject.put("variety", "NORMAL"); + dataObject.put("ordertype", "LIMIT"); + dataObject.put("producttype", "DELIVERY"); + dataObject.put("duration", "DAY"); + dataObject.put("price", 15); + dataObject.put("triggerprice", 0); + dataObject.put("quantity", "1"); + dataObject.put("disclosedquantity", "0"); + dataObject.put("squareoff", 0); + dataObject.put("stoploss", 0); + dataObject.put("trailingstoploss", 0); + dataObject.put("tradingsymbol", "YESBANK-EQ"); + dataObject.put("transactiontype", "BUY"); + dataObject.put("exchange", "NSE"); + dataObject.put("symboltoken", "11915"); + dataObject.put("instrumenttype", ""); + dataObject.put("strikeprice", -1); + dataObject.put("optiontype", ""); + dataObject.put("expirydate", ""); + dataObject.put("lotsize", "1"); + dataObject.put("cancelsize", "0"); + dataObject.put("averageprice", 0); + dataObject.put("filledshares", "0"); + dataObject.put("unfilledshares", "1"); + dataObject.put("orderid", "231009000001039"); + dataObject.put("text", "Invalid User Id"); + dataObject.put("status", "rejected"); + dataObject.put("orderstatus", "rejected"); + dataObject.put("updatetime", "09-Oct-2023 17:39:28"); + dataObject.put("exchtime", ""); + dataObject.put("exchorderupdatetime", ""); + dataObject.put("fillid", ""); + dataObject.put("filltime", ""); + dataObject.put("parentorderid", ""); + dataObject.put("ordertag", ".test"); + dataObject.put("uniqueorderid", "c7db6526-3f32-47c3-a41e-0e5cb6aad365"); + + jsonObject.put("data", dataObject); + return jsonObject; + } + + @Test + public void testIndividualOrder_Success() throws SmartAPIException, IOException { + String url = routes.get("api.individual.order"); + when(smartAPIRequestHandler.getRequest(this.apiKey, url, this.accessToken)).thenReturn(createIndividualOrderResponse()); + try { + JSONObject response = smartAPIRequestHandler.getRequest(this.apiKey, url, this.accessToken); + JSONObject data = response.getJSONObject("data"); + assertNotNull(data); + } catch (SmartAPIException ex) { + log.error("{} while getting individual order {}", SMART_API_EXCEPTION_OCCURRED, ex.toString()); + throw new SmartAPIException(String.format("%s in getting individual order %s", SMART_API_EXCEPTION_ERROR_MSG, ex)); + } + } + + // Testing market data failure for OHLC payload + @Test(expected = SmartAPIException.class) + public void testIndividualOrder_Failure() throws SmartAPIException, IOException { + // Stub the postRequest method + String url = routes.get("api.market.data"); + JSONObject params = getMarketDataRequest("OHLC"); + when(smartAPIRequestHandler.postRequest(eq(this.apiKey), eq(url), eq(params), eq(this.accessToken))) + .thenThrow(new SmartAPIException("API request failed")); + try { + JSONObject response = smartAPIRequestHandler.postRequest(apiKey, url, params, accessToken); + response.getJSONObject("data"); + } catch (SmartAPIException ex) { + log.error("{} while getting individual order {}", SMART_API_EXCEPTION_OCCURRED, ex.toString()); + throw new SmartAPIException(String.format("%s in getting individual order %s", SMART_API_EXCEPTION_ERROR_MSG, ex)); + } + } + +} \ No newline at end of file diff --git a/src/test/java/com/angelbroking/smartapi/orderupdatetest/OrderUpdateTest.java b/src/test/java/com/angelbroking/smartapi/orderupdatetest/OrderUpdateTest.java new file mode 100644 index 00000000..b88bd2bb --- /dev/null +++ b/src/test/java/com/angelbroking/smartapi/orderupdatetest/OrderUpdateTest.java @@ -0,0 +1,74 @@ +package com.angelbroking.smartapi.orderupdatetest; + +import com.angelbroking.smartapi.SmartConnect; +import com.angelbroking.smartapi.models.User; +import com.angelbroking.smartapi.orderupdate.OrderUpdateListner; +import com.angelbroking.smartapi.orderupdate.OrderUpdateWebsocket; +import com.angelbroking.smartapi.smartstream.models.SmartStreamError; +import com.neovisionaries.ws.client.WebSocketException; +import com.warrenstrange.googleauth.GoogleAuthenticator; +import lombok.extern.slf4j.Slf4j; +import org.json.JSONObject; +import org.junit.Test; +import org.junit.jupiter.api.BeforeAll; + +import java.util.Scanner; + +@Slf4j +public class OrderUpdateTest { + private static String clientID; + private static String clientPass; + private static String apiKey; + private static String accessToken; + private static String totp; + + @BeforeAll + public void init(){ + clientID = System.getProperty("clientID"); + clientPass = System.getProperty("clientPass"); + apiKey = System.getProperty("apiKey"); + + Scanner sc = new Scanner(System.in); + log.info("enter totp: "); + totp = sc.nextLine(); + + SmartConnect smartConnect = new SmartConnect(apiKey); + User user = smartConnect.generateSession(clientID, clientPass, totp); + smartConnect.setAccessToken(user.getAccessToken()); + smartConnect.setUserId(user.getUserId()); + accessToken = user.getAccessToken(); + } + + @Test + public void testOrderUpdate_success() throws WebSocketException { + OrderUpdateWebsocket orderUpdateWebsocket = new OrderUpdateWebsocket(accessToken, new OrderUpdateListner() { + @Override + public void onConnected() { + log.info("Connected"); + } + + @Override + public void onDisconnected() { + log.info("Disconnected"); + } + + @Override + public void onError(SmartStreamError error) { + log.info("error {} ",error.getException().getMessage()); + } + + @Override + public void onPong() { + log.info("Pong"); + } + + @Override + public void onOrderUpdate(String data) { + log.info("data {} ",data); + } + }); + + orderUpdateWebsocket.connect(); + + } +} diff --git a/src/test/java/com/angelbroking/smartapi/smartstream/SmartStreamListenerImpl.java b/src/test/java/com/angelbroking/smartapi/smartstream/SmartStreamListenerImpl.java new file mode 100644 index 00000000..229107e8 --- /dev/null +++ b/src/test/java/com/angelbroking/smartapi/smartstream/SmartStreamListenerImpl.java @@ -0,0 +1,125 @@ +package com.angelbroking.smartapi.smartstream; + +import java.time.Instant; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.util.Arrays; + +import com.angelbroking.smartapi.http.exceptions.SmartAPIException; +import com.angelbroking.smartapi.smartstream.models.*; +import com.angelbroking.smartapi.smartstream.ticker.SmartStreamListener; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class SmartStreamListenerImpl implements SmartStreamListener { + + public static final ZoneId TZ_UTC = ZoneId.of("UTC"); + public static final ZoneId TZ_IST = ZoneId.of("Asia/Kolkata"); + + @Override + public void onLTPArrival(LTP ltp) { + ZonedDateTime exchangeTime = ZonedDateTime.ofInstant(Instant.ofEpochMilli(ltp.getExchangeFeedTimeEpochMillis()), TZ_IST); + String ltpData = String.format( + "subscriptionMode: %s exchangeType: %s token: %s sequenceNumber: %d ltp: %.2f exchangeTime: %s exchangeToClientLatency: %s", + SmartStreamSubsMode.findByVal(ltp.getSubscriptionMode()), + ltp.getExchangeType(), ltp.getToken().toString(), ltp.getSequenceNumber(), + (ltp.getLastTradedPrice() / 100.0), exchangeTime, + Instant.now().toEpochMilli() - ltp.getExchangeFeedTimeEpochMillis()); + log.info(ltpData); + } + + @Override + public void onQuoteArrival(Quote quote) { + ZonedDateTime exchangeTime = ZonedDateTime.ofInstant(Instant.ofEpochMilli(quote.getExchangeFeedTimeEpochMillis()), TZ_IST); + String data = String.format("token: %s" + + " sequenceNumber: %d" + + " ltp: %.2f" + + " open: %.2f" + + " high: %.2f" + + " low: %.2f" + + " close: %.2f" + + " exchangeTime: %s" + + " exchangeToClientLatency: %s", + quote.getToken().toString(), + quote.getSequenceNumber(), + (quote.getLastTradedPrice() / 100.0), + (quote.getOpenPrice() / 100.0), + (quote.getHighPrice() / 100.0), + (quote.getLowPrice() / 100.0), + (quote.getClosePrice() / 100.0), + exchangeTime, + Instant.now().toEpochMilli() - quote.getExchangeFeedTimeEpochMillis()); + log.info(data); + } + + @Override + public void onSnapQuoteArrival(SnapQuote snapQuote) { + String snapQuoteData = String.format( + "subscriptionMode: %s exchangeType: %s token: %s sequenceNumber: %d ltp: %.2f lastTradedQty: %d avgTradedPrice: %.2f volumeTradedToday: %d totalBuyQty: %.2f totalSellQty: %.2f open: %.2f high: %.2f low: %.2f close: %.2f " + + "lastTradedTimestamp: %s openInterest: %.2f openInterestChangePerc: %.2f bestFiveBuyData: %s bestFiveSellData: %s upperCircuit: %.2f lowerCircuit: %.2f yearlyHighPrice: %.2f yearlyLowPrice: %.2f exchangeTime: %s exchangeToClientLatency: %s", + SmartStreamSubsMode.findByVal(snapQuote.getSubscriptionMode()), + snapQuote.getExchangeType(), snapQuote.getToken().toString(), + snapQuote.getSequenceNumber(), (snapQuote.getLastTradedPrice() / 100.0), snapQuote.getLastTradedQty(), + (snapQuote.getAvgTradedPrice() / 100.0), snapQuote.getVolumeTradedToday(), snapQuote.getTotalBuyQty(), + snapQuote.getTotalSellQty(), (snapQuote.getOpenPrice() / 100.0), (snapQuote.getHighPrice() / 100.0), + (snapQuote.getLowPrice() / 100.0), (snapQuote.getClosePrice() / 100.0), + snapQuote.getLastTradedTimestamp(), (snapQuote.getOpenInterest() / 100.0), + (snapQuote.getOpenInterestChangePerc()), Arrays.toString(snapQuote.getBestFiveBuy()), + Arrays.toString(snapQuote.getBestFiveSell()), (snapQuote.getUpperCircuit() / 100.0), + (snapQuote.getLowerCircuit() / 100.0), (snapQuote.getYearlyHighPrice() / 100.0), + (snapQuote.getYearlyLowPrice() / 100.0), getExchangeTime(snapQuote.getExchangeFeedTimeEpochMillis()), + Instant.now().toEpochMilli() - snapQuote.getExchangeFeedTimeEpochMillis()); + log.info(snapQuoteData); + } + + @Override + public void onDepthArrival(Depth depth) { + String depthData = String.format( + "subscriptionMode: %s exchangeType: %s token: %s exchangeTimeStamp: %s packetReceivedTime: %s bestTwentyBuyData: %s bestTwentySellData: %s", + SmartStreamSubsMode.findByVal(depth.getSubscriptionMode()), + depth.getExchangeType(), depth.getToken().toString(), + depth.getExchangeTimeStamp(), + depth.getPacketReceivedTime(), + Arrays.toString(depth.getBestTwentyBuyData()), + Arrays.toString(depth.getBestTwentySellData())); + log.info(depthData); + } + + private ZonedDateTime getExchangeTime(long exchangeFeedTimeEpochMillis) { + return ZonedDateTime.ofInstant(Instant.ofEpochMilli(exchangeFeedTimeEpochMillis), TZ_IST); + } + + @Override + public void onConnected() { + // TODO Auto-generated method stub + + } + + @Override + public void onError(SmartStreamError error) { + error.getException().printStackTrace(); + } + + @Override + public void onPong() { + log.info("pong received"); + } + + /* Custom on error method for SmartStream */ + @Override + public SmartStreamError onErrorCustom() { + // User thrown error return + log.info("on custom error"); + SmartStreamError smartStreamError = new SmartStreamError(); + smartStreamError.setException(new SmartAPIException("custom error received")); + return smartStreamError; + } + + @Override + public void onDisconnected() { + // TODO Auto-generated method stub + + } + +} diff --git a/src/test/java/com/angelbroking/smartapi/smartstream/SmartStreamTickerTest.java b/src/test/java/com/angelbroking/smartapi/smartstream/SmartStreamTickerTest.java new file mode 100644 index 00000000..b1aefa16 --- /dev/null +++ b/src/test/java/com/angelbroking/smartapi/smartstream/SmartStreamTickerTest.java @@ -0,0 +1,115 @@ +package com.angelbroking.smartapi.smartstream; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; + +import java.util.HashSet; +import java.util.Scanner; +import java.util.Set; + +import lombok.extern.slf4j.Slf4j; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import com.angelbroking.smartapi.SmartConnect; +import com.angelbroking.smartapi.models.User; +import com.angelbroking.smartapi.smartstream.models.ExchangeType; +import com.angelbroking.smartapi.smartstream.models.SmartStreamSubsMode; +import com.angelbroking.smartapi.smartstream.models.TokenID; +import com.angelbroking.smartapi.smartstream.ticker.SmartStreamTicker; +import com.neovisionaries.ws.client.WebSocketException; +@Slf4j +public class SmartStreamTickerTest { + + private static String clientID; + private static String clientPass; + private static String apiKey; + private static String feedToken; + private static String totp; + + @BeforeAll + public static void initClass() throws InterruptedException { + clientID = System.getProperty("clientID"); + clientPass = System.getProperty("clientPass"); + apiKey = System.getProperty("apiKey"); + + Scanner sc = new Scanner(System.in); + log.info("enter totp: "); + totp = sc.nextLine(); + + SmartConnect smartConnect = new SmartConnect(apiKey); + User user = smartConnect.generateSession(clientID, clientPass, totp); + feedToken = user.getFeedToken(); +// feedToken = "123"; + } + + @Test + void testSmartStreamTicketLTP() throws WebSocketException, InterruptedException { + try { + SmartStreamTicker ticker = new SmartStreamTicker(clientID, feedToken, new SmartStreamListenerImpl()); + ticker.connect(); + ticker.subscribe(SmartStreamSubsMode.QUOTE, getTokens()); +// ticker.subscribe(SmartStreamSubsMode.SNAP_QUOTE, getTokens()); + // uncomment the below line to allow test thread to keep running so that ticks + // can be received in the listener +// Thread.sleep(5000); + ticker.disconnect(); + log.info("isConnected = "+ticker.isConnectionOpen()); + } catch (Exception e) { + e.printStackTrace(); + throw e; + } + + } + + @Test + void testSmartStreamTicket_WithInitialDelayAndPeriod() throws WebSocketException, InterruptedException { + try { + SmartStreamTicker ticker = new SmartStreamTicker(clientID, feedToken, new SmartStreamListenerImpl(), 6000, 6000); + ticker.connect(); + ticker.subscribe(SmartStreamSubsMode.SNAP_QUOTE, getTokens()); +// ticker.subscribe(SmartStreamSubsMode.SNAP_QUOTE, getTokens()); + // uncomment the below line to allow test thread to keep running so that ticks + // can be received in the listener +// Thread.sleep(5000); + ticker.disconnect(); + System.out.println("isConnected = "+ticker.isConnectionOpen()); + } catch (Exception e) { + e.printStackTrace(); + throw e; + } + + } + + private Set getTokens(){ + // find out the required token from https://margincalculator.angelbroking.com/OpenAPI_File/files/OpenAPIScripMaster.json + Set tokenSet = new HashSet<>(); + tokenSet.add(new TokenID(ExchangeType.NSE_CM, "26000")); // NIFTY + tokenSet.add(new TokenID(ExchangeType.NSE_CM, "26009")); // NIFTY BANK + tokenSet.add(new TokenID(ExchangeType.BSE_CM, "19000")); // Sensex + + tokenSet.add(new TokenID(ExchangeType.NSE_CM, "99926000")); // NIFTY + tokenSet.add(new TokenID(ExchangeType.NSE_CM, "99926009")); // NIFTY BANK + tokenSet.add(new TokenID(ExchangeType.BSE_CM, "99919000")); // Sensex + + tokenSet.add(new TokenID(ExchangeType.NSE_CM, "1594")); // NSE Infosys + tokenSet.add(new TokenID(ExchangeType.NSE_FO, "35003")); // Nifty June 2023 FUT + tokenSet.add(new TokenID(ExchangeType.CDE_FO, "1185")); // 1185 USDINR + tokenSet.add(new TokenID(ExchangeType.BSE_CM, "532540")); // BSE TCS + tokenSet.add(new TokenID(ExchangeType.NCX_FO, "GUARGUM5")); // GUAREX (NCDEX) + tokenSet.add(new TokenID(ExchangeType.MCX_FO, "252453")); //CRUDEOIL + return tokenSet; + } + + @Test + void testTokenID() { + TokenID t1 = new TokenID(ExchangeType.NSE_CM, "1594"); + TokenID t2 = new TokenID(ExchangeType.NSE_CM, "4717"); + TokenID t3 = new TokenID(ExchangeType.NSE_CM, "1594"); + TokenID t4 = new TokenID(ExchangeType.NCX_FO, "GUAREX31MAR2022"); + + assertNotEquals(t1, t2); + assertEquals(t1, t3); + + } +} \ No newline at end of file