package com.zerodhatech.kiteconnect; import com.google.gson.*; import com.google.gson.reflect.TypeToken; import com.zerodhatech.kiteconnect.kitehttp.KiteRequestHandler; import com.zerodhatech.kiteconnect.kitehttp.SessionExpiryHook; import com.zerodhatech.kiteconnect.kitehttp.exceptions.KiteException; import com.zerodhatech.kiteconnect.utils.Constants; import com.zerodhatech.models.*; import org.apache.commons.codec.digest.DigestUtils; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import org.supercsv.cellprocessor.*; import org.supercsv.cellprocessor.constraint.NotNull; import org.supercsv.cellprocessor.ift.CellProcessor; import org.supercsv.io.CsvBeanReader; import org.supercsv.io.ICsvBeanReader; import org.supercsv.prefs.CsvPreference; import java.io.*; import java.lang.reflect.Type; import java.net.Proxy; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.*; /** * Offers all the functionality like placing order, fetch margins, orderbook, positions, fetch market snap quote. */ public class KiteConnect { public static SessionExpiryHook sessionExpiryHook = null; public static boolean ENABLE_LOGGING = false; private Proxy proxy = null; private String apiKey; private String accessToken; private String publicToken; private Routes routes = new Routes(); private String userId; private Gson gson; private KiteRequestHandler kiteRequestHandler; /** Initializes KiteSDK with the api key provided for your app. * @param apiKey is the api key provided after creating new Kite Connect app on developers console. */ public KiteConnect(String apiKey){ this(apiKey, null, false); } /** Initializes KiteSDK with the api key provided for your app. * @param apiKey is the api key provided after creating new Kite Connect app on developers console. * @param enableDebugLog is a boolean to enable debug logs */ public KiteConnect(String apiKey, boolean enableDebugLog){ this(apiKey, null, enableDebugLog); } /** Initializes KiteSDK with the api key provided for your app. * @param apiKey is the api key provided after creating new Kite Connect app on developers console. * @param userProxy is the user defined proxy. Can be used only if a user chose to use the proxy. */ public KiteConnect(String apiKey, Proxy userProxy, boolean enableDebugLog) { this.proxy = userProxy; this.apiKey = apiKey; GsonBuilder gsonBuilder = new GsonBuilder(); gsonBuilder.registerTypeAdapter(Date.class, new JsonDeserializer<Date>() { @Override public Date deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException { try { SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); return format.parse(jsonElement.getAsString()); } catch (ParseException e) { return null; } } }); gson = gsonBuilder.setDateFormat("yyyy-MM-dd HH:mm:ss").create(); ENABLE_LOGGING = enableDebugLog; kiteRequestHandler = new KiteRequestHandler(proxy); } /** Registers callback for session error. * @param hook can be set to get callback when session is expired. * */ public void setSessionExpiryHook(SessionExpiryHook hook){ sessionExpiryHook = hook; } /** * Returns apiKey of the App. * @return String apiKey is returned. * @throws NullPointerException if _apiKey is not found. */ public String getApiKey() throws NullPointerException{ if (apiKey != null) return apiKey; else throw new NullPointerException(); } /** * Returns accessToken. * @return String access_token is returned. * @throws NullPointerException if accessToken is null. */ public String getAccessToken() throws NullPointerException{ if(accessToken != null) return accessToken; else throw new NullPointerException(); } /** Returns userId. * @return String userId is returned. * @throws NullPointerException if userId is null.*/ public String getUserId() throws NullPointerException{ if(userId != null) { return userId; }else { throw new NullPointerException(); } } /** Set userId. * @param id is user_id. */ public void setUserId(String id){ userId = id; } /** Returns publicToken. * @throws NullPointerException if publicToken is null. * @return String public token is returned. * */ public String getPublicToken() throws NullPointerException{ if(publicToken != null){ return publicToken; }else { throw new NullPointerException(); } } /** * Set the accessToken received after a successful authentication. * @param accessToken is the access token received after sending request token and api secret. */ public void setAccessToken(String accessToken){ this.accessToken = accessToken; } /** * Set publicToken. * @param publicToken is the public token received after sending request token and api secret. * */ public void setPublicToken(String publicToken){ this.publicToken = publicToken; } /** Retrieves login url * @return String loginUrl is returned. */ public String getLoginURL() throws NullPointerException{ String baseUrl = routes.getLoginUrl(); return baseUrl+"?api_key="+apiKey+"&v=3"; } /** * 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. * @throws KiteException is thrown for all Kite trade related errors. * @throws JSONException is thrown when there is exception while parsing response. * @throws IOException is thrown when there is connection error. */ public User generateSession(String requestToken, String apiSecret) throws KiteException, JSONException, IOException { // Create the checksum needed for authentication. String hashableText = this.apiKey + requestToken + apiSecret; String sha256hex = sha256Hex(hashableText); // Create JSON params object needed to be sent to api. Map<String, Object> params = new HashMap<String, Object>(); params.put("api_key", apiKey); params.put("request_token", requestToken); params.put("checksum", sha256hex); return new User().parseResponse(kiteRequestHandler.postRequest(routes.get("api.validate"), params, apiKey, accessToken)); } /** 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. * @throws IOException is thrown when there is connection error. * @throws KiteException is thrown for all Kite trade related errors. */ public TokenSet renewAccessToken(String refreshToken, String apiSecret) throws IOException, KiteException, JSONException { String hashableText = this.apiKey + refreshToken + apiSecret; String sha256hex = sha256Hex(hashableText); Map<String, Object> params = new HashMap<>(); params.put("api_key", apiKey); params.put("refresh_token", refreshToken); params.put("checksum", sha256hex); JSONObject response = kiteRequestHandler.postRequest(routes.get("api.refresh"), params, apiKey, accessToken); return gson.fromJson(String.valueOf(response.get("data")), TokenSet.class); } /** Hex encodes sha256 output for android support. * @return Hex encoded String. * @param str is the String that has to be encrypted. * */ public String sha256Hex(String str) { byte[] a = DigestUtils.sha256(str); StringBuilder sb = new StringBuilder(a.length * 2); for(byte b: a) sb.append(String.format("%02x", b)); return sb.toString(); } /** Get the profile details of the use. * @return Profile is a POJO which contains profile related data. * @throws IOException is thrown when there is connection error. * @throws KiteException is thrown for all Kite trade related errors.*/ public Profile getProfile() throws IOException, KiteException, JSONException { String url = routes.get("user.profile"); JSONObject response = kiteRequestHandler.getRequest(url, apiKey, accessToken); return gson.fromJson(String.valueOf(response.get("data")), Profile.class); } /** * Gets account balance and cash margin details for a particular segment. * Example for segment can be equity or commodity. * @param segment can be equity or commodity. * @return Margins object. * @throws KiteException is thrown for all Kite trade related errors. * @throws JSONException is thrown when there is exception while parsing response. * @throws IOException is thrown when there is connection error. */ public Margin getMargins(String segment) throws KiteException, JSONException, IOException { String url = routes.get("user.margins.segment").replace(":segment", segment); JSONObject response = kiteRequestHandler.getRequest(url, apiKey, accessToken); return gson.fromJson(String.valueOf(response.get("data")), Margin.class); } /** * Gets account balance and cash margin details for a equity and commodity. * @return Map of String and Margin is a map of commodity or equity string and funds data. * @throws KiteException is thrown for all Kite trade related errors. * @throws JSONException is thrown when there is exception while parsing response. * @throws IOException is thrown when there is connection error. */ public Map<String, Margin> getMargins() throws KiteException, JSONException, IOException { String url = routes.get("user.margins"); JSONObject response = kiteRequestHandler.getRequest(url, apiKey, accessToken); Type type = new TypeToken<Map<String, Margin>>(){}.getType(); return gson.fromJson(String.valueOf(response.get("data")), type); } /** * 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. * @throws KiteException is thrown for all Kite trade related errors. * @throws JSONException is thrown when there is exception while parsing response. * @throws IOException is thrown when there is connection error. */ public Order placeOrder(OrderParams orderParams, String variety) throws KiteException, JSONException, IOException { String url = routes.get("orders.place").replace(":variety", variety); Map<String, Object> params = new HashMap<>(); if(orderParams.exchange != null) params.put("exchange", orderParams.exchange); if(orderParams.tradingsymbol != null) params.put("tradingsymbol", orderParams.tradingsymbol); if(orderParams.transactionType != null) params.put("transaction_type", orderParams.transactionType); if(orderParams.quantity != null) params.put("quantity", orderParams.quantity); if(orderParams.price != null) params.put("price", orderParams.price); if(orderParams.product != null) params.put("product", orderParams.product); if(orderParams.orderType != null) params.put("order_type", orderParams.orderType); if(orderParams.validity != null) params.put("validity", orderParams.validity); if(orderParams.disclosedQuantity != null) params.put("disclosed_quantity", orderParams.disclosedQuantity); if(orderParams.triggerPrice != null) params.put("trigger_price", orderParams.triggerPrice); if(orderParams.squareoff != null) params.put("squareoff", orderParams.squareoff); if(orderParams.stoploss != null) params.put("stoploss", orderParams.stoploss); if(orderParams.trailingStoploss != null) params.put("trailing_stoploss", orderParams.trailingStoploss); if(orderParams.tag != null) params.put("tag", orderParams.tag); JSONObject jsonObject = kiteRequestHandler.postRequest(url, params, apiKey, accessToken); Order order = new Order(); order.orderId = jsonObject.getJSONObject("data").getString("order_id"); return order; } /** * Modifies an open order. * * @param orderParams is Order params. * @param variety variety="regular". Order variety can be bo, co, amo, regular. * @param orderId order id of the order being modified. * @return Order object contains only orderId. * @throws KiteException is thrown for all Kite trade related errors. * @throws JSONException is thrown when there is exception while parsing response. * @throws IOException is thrown when there is connection error. */ public Order modifyOrder(String orderId, OrderParams orderParams, String variety) throws KiteException, JSONException, IOException { String url = routes.get("orders.modify").replace(":variety", variety).replace(":order_id", orderId); Map<String, Object> params = new HashMap<>(); if(orderParams.exchange != null) params.put("exchange", orderParams.exchange); if(orderParams.tradingsymbol != null) params.put("tradingsymbol", orderParams.tradingsymbol); if(orderParams.transactionType != null) params.put("transaction_type", orderParams.transactionType); if(orderParams.quantity != null) params.put("quantity", orderParams.quantity); if(orderParams.price != null) params.put("price", orderParams.price); if(orderParams.product != null) params.put("product", orderParams.product); if(orderParams.orderType != null) params.put("order_type", orderParams.orderType); if(orderParams.validity != null) params.put("validity", orderParams.validity); if(orderParams.disclosedQuantity != null) params.put("disclosed_quantity", orderParams.disclosedQuantity); if(orderParams.triggerPrice != null) params.put("trigger_price", orderParams.triggerPrice); if(orderParams.squareoff != null) params.put("squareoff", orderParams.squareoff); if(orderParams.stoploss != null) params.put("stoploss", orderParams.stoploss); if(orderParams.trailingStoploss != null) params.put("trailing_stoploss", orderParams.trailingStoploss); if(orderParams.parentOrderId != null) params.put("parent_order_id", orderParams.parentOrderId); JSONObject jsonObject = kiteRequestHandler.putRequest(url, params, apiKey, accessToken); Order order = new Order(); order.orderId = jsonObject.getJSONObject("data").getString("order_id"); return order; } /** * 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. * @throws KiteException is thrown for all Kite trade related errors. * @throws JSONException is thrown when there is exception while parsing response. * @throws IOException is thrown when there is connection error. */ public Order cancelOrder(String orderId, String variety) throws KiteException, JSONException, IOException { String url = routes.get("orders.cancel").replace(":variety", variety).replace(":order_id", orderId); Map<String, Object> params = new HashMap<String, Object>(); JSONObject jsonObject = kiteRequestHandler.deleteRequest(url, params, apiKey, accessToken); Order order = new Order(); order.orderId = jsonObject.getJSONObject("data").getString("order_id"); return order; } /** * Cancel/exit special orders like BO, CO * @param parentOrderId order id of first leg. * @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. * @throws KiteException is thrown for all Kite trade related errors. * @throws IOException is thrown when there is connection error. * */ public Order cancelOrder(String orderId, String parentOrderId, String variety) throws KiteException, IOException, JSONException { String url = routes.get("orders.cancel").replace(":variety", variety).replace(":order_id", orderId); Map<String, Object> params = new HashMap<>(); params.put("parent_order_id", parentOrderId); JSONObject jsonObject = kiteRequestHandler.deleteRequest(url, params, apiKey, accessToken); Order order = new Order(); order.orderId = jsonObject.getJSONObject("data").getString("order_id"); return order; } /** Fetches collection of orders from the orderbook. * @return List of orders. * @throws KiteException is thrown for all Kite trade related errors. * @throws JSONException is thrown when there is exception while parsing response. * @throws IOException is thrown when there is connection error. * */ public List<Order> getOrders() throws KiteException, JSONException, IOException { String url = routes.get("orders"); JSONObject response = kiteRequestHandler.getRequest(url, apiKey, accessToken); return Arrays.asList(gson.fromJson(String.valueOf(response.get("data")), Order[].class)); } /** Fetches list of gtt existing in an account. * @return List of GTTs. * @throws KiteException is thrown for all Kite trade related errors. * @throws IOException is thrown when there is connection error. * */ public List<GTT> getGTTs() throws KiteException, IOException, JSONException { String url = routes.get("gtt"); JSONObject response = kiteRequestHandler.getRequest(url, apiKey, accessToken); return Arrays.asList(gson.fromJson(String.valueOf(response.get("data")), GTT[].class)); } /** Fetch details of a GTT. * @param gttId is the id of the GTT that needs to be fetched. * @return GTT object which contains all the details. * @throws KiteException is thrown for all Kite trade related errors. * @throws IOException is thrown when there is connection error. * @throws JSONException is thrown when there is exception while parsing response. * */ public GTT getGTT(int gttId) throws IOException, KiteException, JSONException { String url = routes.get("gtt.info").replace(":id", gttId+""); JSONObject response = kiteRequestHandler.getRequest(url, apiKey, accessToken); return gson.fromJson(String.valueOf(response.get("data")), GTT.class); } /** Place a GTT. * @param gttParams is GTT param which container condition, type, order details. It can contain one or two orders. * @throws IOException is thrown when there is connection error. * @throws KiteException is thrown for all Kite trade related errors. * @throws JSONException is thrown when there is exception while parsing response. * @return GTT object contains only gttId.*/ public GTT placeGTT(GTTParams gttParams) throws IOException, KiteException, JSONException { String url = routes.get("gtt.place"); Map<String, Object> params = new HashMap<>(); Map<String, Object> conditionParam = new HashMap<>(); JSONArray ordersParam = new JSONArray(); conditionParam.put("exchange", gttParams.exchange); conditionParam.put("tradingsymbol", gttParams.tradingsymbol); conditionParam.put("trigger_values", gttParams.triggerPrices.toArray()); conditionParam.put("last_price", gttParams.lastPrice); conditionParam.put("instrument_token", gttParams.instrumentToken); for(GTTParams.GTTOrderParams order : gttParams.orders) { JSONObject gttOrderItem = new JSONObject(); gttOrderItem.put("exchange", gttParams.exchange); gttOrderItem.put("tradingsymbol", gttParams.tradingsymbol); gttOrderItem.put("transaction_type", order.transactionType); gttOrderItem.put("quantity", order.quantity); gttOrderItem.put("price", order.price); gttOrderItem.put("order_type", order.orderType); gttOrderItem.put("product", order.product); ordersParam.put(gttOrderItem); } params.put("condition", new JSONObject(conditionParam).toString()); params.put("orders", ordersParam.toString()); params.put("type", gttParams.triggerType); JSONObject response = kiteRequestHandler.postRequest(url, params, apiKey, accessToken); GTT gtt = new GTT(); gtt.id = response.getJSONObject("data").getInt("trigger_id"); return gtt; } /** Modify a GTT. * @param gttParams is GTT param which container condition, type, order details. It can contain one or two orders. * @param gttId is the id of the GTT to be modified. * @throws IOException is thrown when there is connection error. * @throws KiteException is thrown for all Kite trade related errors. * @throws JSONException is thrown when there is exception while parsing response. * @return GTT object contains only gttId.*/ public GTT modifyGTT(int gttId, GTTParams gttParams) throws IOException, KiteException, JSONException { String url = routes.get("gtt.modify").replace(":id", gttId+""); Map<String, Object> params = new HashMap<>(); Map<String, Object> conditionParam = new HashMap<>(); JSONArray ordersParam = new JSONArray(); conditionParam.put("exchange", gttParams.exchange); conditionParam.put("tradingsymbol", gttParams.tradingsymbol); conditionParam.put("trigger_values", gttParams.triggerPrices.toArray()); conditionParam.put("last_price", gttParams.lastPrice); conditionParam.put("instrument_token", gttParams.instrumentToken); for(GTTParams.GTTOrderParams order : gttParams.orders) { JSONObject gttOrderItem = new JSONObject(); gttOrderItem.put("exchange", gttParams.exchange); gttOrderItem.put("tradingsymbol", gttParams.tradingsymbol); gttOrderItem.put("transaction_type", order.transactionType); gttOrderItem.put("quantity", order.quantity); gttOrderItem.put("price", order.price); gttOrderItem.put("order_type", order.orderType); gttOrderItem.put("product", order.product); ordersParam.put(gttOrderItem); } params.put("condition", new JSONObject(conditionParam).toString()); params.put("orders", ordersParam.toString()); params.put("type", gttParams.triggerType); JSONObject response = kiteRequestHandler.putRequest(url, params, apiKey, accessToken); GTT gtt = new GTT(); gtt.id = response.getJSONObject("data").getInt("trigger_id"); return gtt; } /** * Cancel GTT. * @param gttId order id of first leg. * @return GTT object contains only gttId. * @throws KiteException is thrown for all Kite trade related errors. * @throws IOException is thrown when there is connection error. * @throws JSONException is thrown when there is exception while parsing response. * */ public GTT cancelGTT(int gttId) throws IOException, KiteException, JSONException { String url = routes.get("gtt.delete").replace(":id", gttId+""); JSONObject response = kiteRequestHandler.deleteRequest(url, new HashMap<>(), apiKey, accessToken); GTT gtt = new GTT(); gtt.id = response.getJSONObject("data").getInt("trigger_id"); return gtt; } /** Returns list of different stages an order has gone through. * @return List of multiple stages an order has gone through in the system. * @throws KiteException is thrown for all Kite trade related errors. * @param orderId is the order id which is obtained from orderbook. * @throws KiteException is thrown for all Kite trade related errors. * @throws IOException is thrown when there is connection error. * */ public List<Order> getOrderHistory(String orderId) throws KiteException, IOException, JSONException { String url = routes.get("order").replace(":order_id", orderId); JSONObject response = kiteRequestHandler.getRequest(url, apiKey, accessToken); return Arrays.asList(gson.fromJson(String.valueOf(response.get("data")), Order[].class)); } /** * Retrieves list of trades executed. * @return List of trades. * @throws KiteException is thrown for all Kite trade related errors. * @throws JSONException is thrown when there is exception while parsing response. * @throws IOException is thrown when there is connection error. */ public List<Trade> getTrades() throws KiteException, JSONException, IOException { JSONObject response = kiteRequestHandler.getRequest(routes.get("trades"), apiKey, accessToken); return Arrays.asList(gson.fromJson(String.valueOf(response.get("data")), Trade[].class)); } /** * Retrieves list of trades executed of an order. * @param orderId order if of the order whose trades are fetched. * @return List of trades for the given order. * @throws KiteException is thrown for all Kite trade related errors. * @throws JSONException is thrown when there is exception while parsing response. * @throws IOException is thrown when there is connection error. */ public List<Trade> getOrderTrades(String orderId) throws KiteException, JSONException, IOException { JSONObject response = kiteRequestHandler.getRequest(routes.get("orders.trades").replace(":order_id", orderId), apiKey, accessToken); return Arrays.asList(gson.fromJson(String.valueOf(response.get("data")), Trade[].class)); } /** * Retrieves the list of holdings. * @return List of holdings. * @throws KiteException is thrown for all Kite trade related errors. * @throws JSONException is thrown when there is exception while parsing response. * @throws IOException is thrown when there is connection error. */ public List<Holding> getHoldings() throws KiteException, JSONException, IOException { JSONObject response = kiteRequestHandler.getRequest(routes.get("portfolio.holdings"), apiKey, accessToken); return Arrays.asList(gson.fromJson(String.valueOf(response.get("data")), Holding[].class)); } /** * Retrieves the list of positions. * @return List of positions. * @throws KiteException is thrown for all Kite trade related errors. * @throws JSONException is thrown when there is exception while parsing response. * @throws IOException is thrown when there is connection error. */ public Map<String, List<Position>> getPositions() throws KiteException, JSONException, IOException { Map<String, List<Position>> positionsMap = new HashMap<>(); JSONObject response = kiteRequestHandler.getRequest(routes.get("portfolio.positions"), apiKey, accessToken); JSONObject allPositions = response.getJSONObject("data"); positionsMap.put("net", Arrays.asList(gson.fromJson(String.valueOf(allPositions.get("net")), Position[].class))); positionsMap.put("day", Arrays.asList(gson.fromJson(String.valueOf(allPositions.get("day")), Position[].class))); return positionsMap; } /** * Modifies an open position's product type. Only an MIS, CNC, and NRML positions can be converted. * @param tradingSymbol Tradingsymbol of the instrument (ex. RELIANCE, INFY). * @param exchange Exchange in which instrument is listed (NSE, BSE, NFO, BFO, CDS, MCX). * @param transactionType Transaction type (BUY or SELL). * @param positionType day or overnight position * @param oldProduct Product code (NRML, MIS, CNC). * @param newProduct Product code (NRML, MIS, CNC). * @param quantity Order quantity * @return JSONObject which will have status. * @throws KiteException is thrown for all Kite trade related errors. * @throws JSONException is thrown when there is exception while parsing response. * @throws IOException is thrown when there is connection error. */ public JSONObject convertPosition(String tradingSymbol, String exchange, String transactionType, String positionType, String oldProduct, String newProduct, int quantity) throws KiteException, JSONException, IOException { Map<String, Object> params = new HashMap<>(); params.put("tradingsymbol", tradingSymbol); params.put("exchange", exchange); params.put("transaction_type", transactionType); params.put("position_type", positionType); params.put("old_product", oldProduct); params.put("new_product", newProduct); params.put("quantity", quantity); return kiteRequestHandler.putRequest(routes.get("portfolio.positions.modify"), params, apiKey, accessToken); } /** * Retrieves list of market instruments available to trade. * * Response is array for objects. For example, * { * instrument_token: '131098372', * exchange_token: '512103', * tradingsymbol: 'NIDHGRN', * name: 'NIDHI GRANITES', * last_price: '0.0', * expiry: '', * strike: '0.0', * tick_size: '0.05', * lot_size: '1', * instrument_type: 'EQ', * segment: 'BSE', * exchange: 'BSE' }, ...] * @return List of instruments which are available to trade. * @throws KiteException is thrown for all Kite trade related errors. * @throws IOException is thrown when there is connection related errors. */ public List<Instrument> getInstruments() throws KiteException, IOException, JSONException { return readCSV(kiteRequestHandler.getCSVRequest(routes.get("market.instruments.all"), apiKey, accessToken)); } /** * Retrieves list of market instruments available to trade for an exchange * * Response is array for objects. For example, * { * instrument_token: '131098372', * exchange_token: '512103', * tradingsymbol: 'NIDHGRN', * name: 'NIDHI GRANITES', * last_price: '0.0', * expiry: '', * strike: '0.0', * tick_size: '0.05', * lot_size: '1', * instrument_type: 'EQ', * segment: 'BSE', * exchange: 'BSE' }, ...] * @param exchange Filter instruments based on exchange. exchange can be NSE, BSE, NFO, BFO, CDS, MCX. * @return List of instruments which are available to trade for an exchange. * @throws KiteException is thrown for all Kite trade related errors. * @throws JSONException is thrown when there is exception while parsing response. * @throws IOException is thrown when there is connection related error. */ public List<Instrument> getInstruments(String exchange) throws KiteException, JSONException, IOException { return readCSV(kiteRequestHandler.getCSVRequest(routes.get("market.instruments").replace(":exchange", exchange), apiKey, accessToken)); } /** * Retrieves quote and market depth for an instrument * * @param instruments is the array of tradingsymbol and exchange or instrument token. For example {NSE:NIFTY 50, BSE:SENSEX} or {256265, 265} * * @return Map of String and Quote. * @throws KiteException is thrown for all Kite trade related errors. * @throws JSONException is thrown when there is exception while parsing response. * @throws IOException is thrown when there is connection related error. */ public Map<String, Quote> getQuote(String [] instruments) throws KiteException, JSONException, IOException { JSONObject jsonObject = kiteRequestHandler.getRequest(routes.get("market.quote"), "i", instruments, apiKey, accessToken); Type type = new TypeToken<Map<String, Quote>>(){}.getType(); return gson.fromJson(String.valueOf(jsonObject.get("data")), type); } /** Retrieves OHLC and 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 OHLCQuote. * @param instruments is the array of tradingsymbol and exchange or instruments token. * @throws KiteException is thrown for all Kite trade related errors. * @throws IOException is thrown when there is connection related error. * */ public Map<String, OHLCQuote> getOHLC(String [] instruments) throws KiteException, IOException, JSONException { JSONObject resp = kiteRequestHandler.getRequest(routes.get("quote.ohlc"), "i", instruments, apiKey, accessToken); Type type = new TypeToken<Map<String, OHLCQuote>>(){}.getType(); return gson.fromJson(String.valueOf(resp.get("data")), type); } /** 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. * @param instruments is the array of tradingsymbol and exchange or instruments token. * @throws KiteException is thrown for all Kite trade related errors. * @throws IOException is thrown when there is connection related error. * */ public Map<String, LTPQuote> getLTP(String[] instruments) throws KiteException, IOException, JSONException { JSONObject response = kiteRequestHandler.getRequest(routes.get("quote.ltp"), "i", instruments, apiKey, accessToken); Type type = new TypeToken<Map<String, LTPQuote>>(){}.getType(); return gson.fromJson(String.valueOf(response.get("data")), type); } /** * Retrieves buy or sell trigger range for Cover Orders. * @return TriggerRange object is returned. * @param instruments is the array of tradingsymbol and exchange or instrument token. * @param transactionType "BUY or "SELL". * @throws KiteException is thrown for all Kite trade related errors. * @throws JSONException is thrown when there is exception while parsing response. * @throws IOException is thrown when there is connection related error. */ public Map<String, TriggerRange> getTriggerRange(String[] instruments, String transactionType) throws KiteException, JSONException, IOException { String url = routes.get("market.trigger_range").replace(":transaction_type", transactionType.toLowerCase()); JSONObject response = kiteRequestHandler.getRequest(url, "i", instruments, apiKey, accessToken); Type type = new TypeToken<Map<String, TriggerRange>>(){}.getType(); return gson.fromJson(String.valueOf(response.get("data")), type); } /** Retrieves historical data for an instrument. * @param from "yyyy-mm-dd" for fetching candles between days and "yyyy-mm-dd hh:mm:ss" for fetching candles between timestamps. * @param to "yyyy-mm-dd" for fetching candles between days and "yyyy-mm-dd hh:mm:ss" for fetching candles between timestamps. * @param continuous set to true for fetching continuous data of expired instruments. * @param interval can be minute, day, 3minute, 5minute, 10minute, 15minute, 30minute, 60minute. * @param token is instruments token. * @param oi set to true for fetching open interest data. The default value is 0. * @return HistoricalData object which contains list of historical data termed as dataArrayList. * @throws KiteException is thrown for all Kite trade related errors. * @throws IOException is thrown when there is connection related error. * */ public HistoricalData getHistoricalData(Date from, Date to, String token, String interval, boolean continuous, boolean oi) throws KiteException, IOException, JSONException { SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); Map<String, Object> params = new HashMap<>(); params.put("from", format.format(from)); params.put("to", format.format(to)); params.put("continuous", continuous ? 1 : 0); params.put("oi", oi ? 1 : 0); String url = routes.get("market.historical").replace(":instrument_token", token).replace(":interval", interval); HistoricalData historicalData = new HistoricalData(); historicalData.parseResponse(kiteRequestHandler.getRequest(url, params, apiKey, accessToken)); return historicalData; } /** Retrieves mutualfunds instruments. * @return returns list of mutual funds instruments. * @throws KiteException is thrown for all Kite trade related errors. * @throws IOException is thrown when there is connection related errors. * */ public List<MFInstrument> getMFInstruments() throws KiteException, IOException, JSONException { return readMfCSV(kiteRequestHandler.getCSVRequest(routes.get("mutualfunds.instruments"), apiKey, accessToken)); } /** Place a mutualfunds order. * @return MFOrder object contains only orderId. * @param tradingsymbol Tradingsymbol (ISIN) of the fund. * @param transactionType BUY or SELL. * @param amount Amount worth of units to purchase. Not applicable on SELLs. * @param quantity Quantity to SELL. Not applicable on BUYs. If the holding is less than minimum_redemption_quantity, all the units have to be sold. * @param tag An optional tag to apply to an order to identify it (alphanumeric, max 8 chars). * @throws KiteException is thrown for all Kite trade related errors. * @throws IOException is thrown when there is connection related error. * */ public MFOrder placeMFOrder(String tradingsymbol, String transactionType, double amount, double quantity, String tag) throws KiteException, IOException, JSONException { Map<String, Object> params = new HashMap<String, Object>(); params.put("tradingsymbol", tradingsymbol); params.put("transaction_type", transactionType); params.put("amount", amount); if(transactionType.equals(Constants.TRANSACTION_TYPE_SELL)) params.put("quantity", quantity); params.put("tag", tag); JSONObject response = kiteRequestHandler.postRequest(routes.get("mutualfunds.orders.place"), params, apiKey, accessToken); MFOrder MFOrder = new MFOrder(); MFOrder.orderId = response.getJSONObject("data").getString("order_id"); return MFOrder; } /** If cancel is successful then api will respond as 200 and send back true else it will be sent back to user as KiteException. * @return true if api call is successful. * @param orderId is the order id of the mutualfunds order. * @throws KiteException is thrown for all Kite trade related errors. * @throws IOException is thrown when there connection related error. * */ public boolean cancelMFOrder(String orderId) throws KiteException, IOException, JSONException { kiteRequestHandler.deleteRequest(routes.get("mutualfunds.cancel_order").replace(":order_id", orderId), new HashMap<String, Object>(), apiKey, accessToken); return true; } /** Retrieves all mutualfunds orders. * @return List of all the mutualfunds orders. * @throws KiteException is thrown for all Kite trade related errors. * @throws IOException is thrown when there is connection related error. * */ public List<MFOrder> getMFOrders() throws KiteException, IOException, JSONException { JSONObject response = kiteRequestHandler.getRequest(routes.get("mutualfunds.orders"), apiKey, accessToken); return Arrays.asList(gson.fromJson(String.valueOf(response.get("data")), MFOrder[].class)); } /** Retrieves individual mutualfunds order. * @param orderId is the order id of a mutualfunds scrip. * @return returns a single mutualfunds object with all the parameters. * @throws KiteException is thrown for all Kite trade related errors. * @throws IOException is thrown when there is connection related error. * */ public MFOrder getMFOrder(String orderId) throws KiteException, IOException, JSONException { JSONObject response = kiteRequestHandler.getRequest(routes.get("mutualfunds.order").replace(":order_id", orderId), apiKey, accessToken); return gson.fromJson(response.get("data").toString(), MFOrder.class); } /** Place a mutualfunds sip. * @param tradingsymbol Tradingsymbol (ISIN) of the fund. * @param frequency weekly, monthly, or quarterly. * @param amount Amount worth of units to purchase. It should be equal to or greated than minimum_additional_purchase_amount and in multiple of purchase_amount_multiplier in the instrument master. * @param installmentDay If Frequency is monthly, the day of the month (1, 5, 10, 15, 20, 25) to trigger the order on. * @param instalments Number of instalments to trigger. If set to -1, instalments are triggered at fixed intervals until the SIP is cancelled. * @param initialAmount Amount worth of units to purchase before the SIP starts. Should be equal to or greater than minimum_purchase_amount and in multiple of purchase_amount_multiplier. This is only considered if there have been no prior investments in the target fund. * @return MFSIP object which contains sip id and order id. * @throws KiteException is thrown for all Kite trade related errors. * @throws IOException is thrown when there is connection related error. * */ public MFSIP placeMFSIP(String tradingsymbol, String frequency, int installmentDay, int instalments, int initialAmount, double amount) throws KiteException, IOException, JSONException { Map<String, Object> params = new HashMap<String, Object>(); params.put("tradingsymbol", tradingsymbol); params.put("frequency", frequency); params.put("instalment_day", installmentDay); params.put("instalments", instalments); params.put("initial_amount", initialAmount); params.put("amount", amount); MFSIP MFSIP = new MFSIP(); JSONObject response = kiteRequestHandler.postRequest(routes.get("mutualfunds.sips.place"),params, apiKey, accessToken); MFSIP.orderId = response.getJSONObject("data").getString("order_id"); MFSIP.sipId = response.getJSONObject("data").getString("sip_id"); return MFSIP; } /** Modify a mutualfunds sip. * @param frequency weekly, monthly, or quarterly. * @param status Pause or unpause an SIP (active or paused). * @param amount Amount worth of units to purchase. It should be equal to or greated than minimum_additional_purchase_amount and in multiple of purchase_amount_multiplier in the instrument master. * @param day If Frequency is monthly, the day of the month (1, 5, 10, 15, 20, 25) to trigger the order on. * @param instalments Number of instalments to trigger. If set to -1, instalments are triggered at fixed intervals until the SIP is cancelled. * @param sipId is the id of the sip. * @return returns true, if modify sip is successful else exception is thrown. * @throws KiteException is thrown for all Kite trade related errors. * @throws IOException is thrown when there is connection related error. * */ public boolean modifyMFSIP(String frequency, int day, int instalments, double amount, String status, String sipId) throws KiteException, IOException, JSONException { Map<String, Object> params = new HashMap<String, Object>(); params.put("frequency", frequency); params.put("day", day); params.put("instalments", instalments); params.put("amount", amount); params.put("status", status); kiteRequestHandler.putRequest(routes.get("mutualfunds.sips.modify").replace(":sip_id", sipId), params, apiKey, accessToken); return true; } /** Cancel a mutualfunds sip. * @param sipId is the id of mutualfunds sip. * @return returns true, if cancel sip is successful else exception is thrown. * @throws KiteException is thrown for all Kite trade related errors. * @throws IOException is thrown when there is connection related error. * */ public boolean cancelMFSIP(String sipId) throws KiteException, IOException, JSONException { kiteRequestHandler.deleteRequest(routes.get("mutualfunds.sip").replace(":sip_id", sipId), new HashMap<String, Object>(), apiKey, accessToken); return true; } /** Retrieve all mutualfunds sip. * @return List of sips. * @throws KiteException is thrown for all Kite trade related errors. * @throws IOException is thrown when there is connection related error. * */ public List<MFSIP> getMFSIPs() throws KiteException, IOException, JSONException { JSONObject response = kiteRequestHandler.getRequest(routes.get("mutualfunds.sips"), apiKey, accessToken); return Arrays.asList(gson.fromJson(String.valueOf(response.get("data")), MFSIP[].class)); } /** Retrieve an individual sip. * @param sipId is the id of a particular sip. * @return MFSIP object which contains all the details of the sip. * @throws KiteException is thrown for all Kite trade related errors. * @throws IOException is thrown when there is connection related error. * */ public MFSIP getMFSIP(String sipId) throws KiteException, IOException, JSONException { JSONObject response = kiteRequestHandler.getRequest(routes.get("mutualfunds.sip").replace(":sip_id", sipId), apiKey, accessToken); return gson.fromJson(response.get("data").toString(), MFSIP.class); } /** Retrieve all the mutualfunds holdings. * @return List of mutualfunds holdings. * @throws KiteException is thrown for all Kite trade related errors. * @throws IOException is thrown when there is connection related error. * */ public List<MFHolding> getMFHoldings() throws KiteException, IOException, JSONException { JSONObject response = kiteRequestHandler.getRequest(routes.get("mutualfunds.holdings"), apiKey, accessToken); return Arrays.asList(gson.fromJson(String.valueOf(response.get("data")), MFHolding[].class)); } /** * Logs out user by invalidating the access token. * @return JSONObject which contains status * @throws KiteException is thrown for all Kite trade related errors. * @throws IOException is thrown when there is connection related error. */ public JSONObject logout() throws KiteException, IOException, JSONException { return invalidateAccessToken(); } /** * Kills the session by invalidating the access token. * @return JSONObject which contains status * @throws KiteException is thrown for all Kite trade related errors. * @throws IOException is thrown when there is connection related error. */ public JSONObject invalidateAccessToken() throws IOException, KiteException, JSONException { String url = routes.get("api.token"); Map<String, Object> params = new HashMap<>(); params.put("api_key", apiKey); params.put("access_token", accessToken); return kiteRequestHandler.deleteRequest(url, params, apiKey, accessToken); } /** * Kills the refresh token. * @return JSONObject contains status. * @param refreshToken is the token received after successful log in. * @throws IOException is thrown for connection related errors. * @throws KiteException is thrown for Kite trade related errors. * */ public JSONObject invalidateRefreshToken(String refreshToken) throws IOException, KiteException, JSONException { Map<String, Object> param = new HashMap<>(); param.put("refresh_token", refreshToken); param.put("api_key", apiKey); String url = routes.get("api.token"); return kiteRequestHandler.deleteRequest(url, param, apiKey, accessToken); } /**This method parses csv and returns instrument list. * @param input is csv string. * @return returns list of instruments. * @throws IOException is thrown when there is connection related error. * */ private List<Instrument> readCSV(String input) throws IOException { ICsvBeanReader beanReader = null; File temp = File.createTempFile("tempfile", ".tmp"); BufferedWriter bw = new BufferedWriter(new FileWriter(temp)); bw.write(input); bw.close(); beanReader = new CsvBeanReader(new FileReader(temp), CsvPreference.STANDARD_PREFERENCE); String[] header = beanReader.getHeader(true); CellProcessor[] processors = getProcessors(); Instrument instrument; List<Instrument> instruments = new ArrayList<>(); while((instrument = beanReader.read(Instrument.class, header, processors)) != null ) { instruments.add(instrument); } return instruments; } /**This method parses csv and returns instrument list. * @param input is mutualfunds csv string. * @return returns list of mutualfunds instruments. * @throws IOException is thrown when there is connection related error. * */ private List<MFInstrument> readMfCSV(String input) throws IOException{ ICsvBeanReader beanReader = null; File temp = File.createTempFile("tempfile", ".tmp"); BufferedWriter bw = new BufferedWriter(new FileWriter(temp)); bw.write(input); bw.close(); beanReader = new CsvBeanReader(new FileReader(temp), CsvPreference.STANDARD_PREFERENCE); String[] header = beanReader.getHeader(true); CellProcessor[] processors = getMfProcessors(); MFInstrument instrument; List<MFInstrument> instruments = new ArrayList<>(); while((instrument = beanReader.read(MFInstrument.class, header, processors)) != null ) { instruments.add(instrument); } return instruments; } /** This method returns array of cellprocessor for parsing csv. * @return CellProcessor[] array * */ private CellProcessor[] getProcessors(){ CellProcessor[] processors = new CellProcessor[]{ new NotNull(new ParseLong()), //instrument_token new NotNull(new ParseLong()), //exchange_token new NotNull(), //trading_symbol new org.supercsv.cellprocessor.Optional(), //company name new NotNull(new ParseDouble()), //last_price new org.supercsv.cellprocessor.Optional(new ParseDate("yyyy-MM-dd")), //expiry new org.supercsv.cellprocessor.Optional(), //strike new NotNull(new ParseDouble()), //tick_size new NotNull(new ParseInt()), //lot_size new NotNull(), //instrument_type new NotNull(), //segment new NotNull() //exchange }; return processors; } /** This method returns array of cellprocessor for parsing mutual funds csv. * @return CellProcessor[] array * */ private CellProcessor[] getMfProcessors(){ CellProcessor[] processors = new CellProcessor[]{ new org.supercsv.cellprocessor.Optional(), //tradingsymbol new org.supercsv.cellprocessor.Optional(), //amc new org.supercsv.cellprocessor.Optional(), //name new org.supercsv.cellprocessor.Optional(new ParseBool()), //purchase_allowed new org.supercsv.cellprocessor.Optional(new ParseBool()), //redemption_allowed new org.supercsv.cellprocessor.Optional(new ParseDouble()), //minimum_purchase_amount new org.supercsv.cellprocessor.Optional(new ParseDouble()), //purchase_amount_multiplier new org.supercsv.cellprocessor.Optional(new ParseDouble()), //minimum_additional_purchase_amount new org.supercsv.cellprocessor.Optional(new ParseDouble()), //minimum_redemption_quantity new org.supercsv.cellprocessor.Optional(new ParseDouble()), //redemption_quantity_multiplier new org.supercsv.cellprocessor.Optional(), //dividend_type new org.supercsv.cellprocessor.Optional(), //scheme_type new org.supercsv.cellprocessor.Optional(), //plan new org.supercsv.cellprocessor.Optional(), //settlement_type new org.supercsv.cellprocessor.Optional(new ParseDouble()), //last_price new org.supercsv.cellprocessor.Optional(new ParseDate("yyyy-MM-dd")) //last_price_date }; return processors; } }