diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7003959 --- /dev/null +++ b/.gitignore @@ -0,0 +1,12 @@ +.idea +.php_cs +.php_cs.cache +.phpunit.result.cache +build +composer.lock +coverage +docs +phpunit.xml +psalm.xml +vendor +index.php \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 056b320..1285f84 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ -New features -============= +# Changelog + +All notable changes to `phpkiteconnect` will be documented in this file. + +## 1.0.0 - 202X-XX-XX + +- initial release +#### New Features - method: `getProfile` - method: `getOHLC` - method: `getLTP` @@ -42,9 +48,12 @@ API method name changes Params and other changes ======================== +- `placeOrder` method takes all the params as array including `variety` +- `modifyOrder` method takes all the params as array including `variety` and `order_id` +- `cancelOrder` method takes all the params as array - `convertPosition` method takes all the params as array - `getHistoricalData` method takes all the params as array -- [Changes in `generateSession` response structure](https://kite.trade/docs/connect/v3/user/#response-attributes) +- [Changes in `requestAccessToken` response structure](https://kite.trade/docs/connect/v3/user/#response-attributes) - [Changes in `getPositions` response structure](https://kite.trade/docs/connect/v3/portfolio/#response-attributes_1) - [Changes in `getQuote` response structure](https://kite.trade/docs/connect/v3/market-quotes/#retrieving-full-market-quotes) - [Changes in `placeOrder` params](https://kite.trade/docs/connect/v3/orders/#bracket-order-bo-parameters) diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..a5bb3f1 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) [Zerodha Technology](http://zerodha.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/README.md b/README.md index 3c19125..e6f5901 100644 --- a/README.md +++ b/README.md @@ -1,21 +1,30 @@ # The Kite Connect API PHP client - v3 -The official PHP client for communicating with the [Kite Connect API](https://kite.trade). +The Official PHP client for communicating with the [Kite Connect API](https://kite.trade). Kite Connect 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 portfolio and more, with the simple HTTP API collection. -[Zerodha Technology](http://zerodha.com) (c) 2018. Licensed under the MIT License. +[Zerodha Technology](http://zerodha.com) (c) 2021. Licensed under the MIT License. ## Documentation - [PHP client documentation](https://kite.trade/docs/phpkiteconnect/v3) - [Kite Connect HTTP API documentation](https://kite.trade/docs/connect/v3) ## Installing -Download `kiteconnect.php` and `include()` it in your application. +### Requirements +1. Install [PHP](https://www.php.net/manual/en/install.php) version 7.3 or higher. +2. Install [Composer](https://getcomposer.org/download/), which is used to install PHP packages. + +You can install the package via composer: +```bash +composer require zerodha/phpkiteconnect +``` ## Usage ```php login_url() try { $user = $kite->generateSession("request_token_obtained", "your_api_secret"); - echo "Authentication successful. \n"; print_r($user); - $kite->setAccessToken($user->access_token); } catch(Exception $e) { echo "Authentication failed: ".$e->getMessage(); @@ -42,7 +49,7 @@ Download `kiteconnect.php` and `include()` it in your application. print_r($kite->getPositions()); // Place order. - $o = $kite->placeOrder("regular", [ + $order = $kite->placeOrder("regular", [ "tradingsymbol" => "INFY", "exchange" => "NSE", "quantity" => 1, @@ -51,12 +58,20 @@ Download `kiteconnect.php` and `include()` it in your application. "product" => "NRML" ]); - echo "Order id is ".$o->order_id; + echo "Order id is ".$order->order_id; ?> ``` +## Examples + +Check [examples folder](https://github.com/zerodha/phpkiteconnect/tree/master/examples) for more examples. + Refer to the [PHP client documentation](https://kite.trade/docs/phpkiteconnect/v3) for the complete list of supported methods. -## Changelog -[Check CHANGELOG.md](CHANGELOG.md) +## Run unit tests +``` +phpunit tests/KiteConnectTest.php +``` +## Changelog +[Check CHANGELOG.md](CHANGELOG.md) \ No newline at end of file diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..51f200a --- /dev/null +++ b/composer.json @@ -0,0 +1,52 @@ +{ + "name": "zerodha/phpkiteconnect", + "description": "The PHP client library for the Kite Connect trading APIs Resources", + "type": "library", + "keywords": [ + "zerodha", + "phpkiteconnect" + ], + "homepage": "https://github.com/zerodha/phpkiteconnect", + "license": "MIT", + "authors": [ + { + "name": "zerodha", + "email": "kite@zerodha.com", + "role": "Owner" + } + ], + "require": { + "php": ">=7.3", + "ext-curl": "*", + "ext-json": "*", + "ext-zlib": "*", + "guzzlehttp/guzzle": "^7.2", + "guzzlehttp/psr7": "^1.7" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^2.17", + "phpunit/phpunit": "^9.5", + "vimeo/psalm": "^4.3" + }, + "autoload": { + "psr-4": { + "KiteConnect\\": "src/" + } + }, + "autoload-dev": { + "psr-4": { + "KiteConnect\\Tests\\": "tests" + } + }, + "scripts": { + "psalm": "vendor/bin/psalm", + "test": "vendor/bin/phpunit", + "test-coverage": "vendor/bin/phpunit --coverage-html coverage", + "format": "vendor/bin/php-cs-fixer fix --allow-risky=yes" + }, + "config": { + "sort-packages": true + }, + "minimum-stability": "dev", + "prefer-stable": true +} diff --git a/examples/kiteconnect_sample.php b/examples/kiteconnect_sample.php index fe608e7..f135936 100644 --- a/examples/kiteconnect_sample.php +++ b/examples/kiteconnect_sample.php @@ -1,58 +1,80 @@ login_url() - try { - $user = $kite->generateSession("request_token_obtained", "your_api_secret"); - - echo "Authentication successful. \n"; - print_r($user); - - $kite->setAccessToken($user->access_token); - } catch(Exception $e) { - echo "Authentication failed: ".$e->getMessage(); - throw $e; - } - - echo $user->user_id." has logged in"; - - // Get the list of positions. - echo "Positions: \n"; - print_r($kite->getPositions()); - - // Get the list of holdings. - echo "Holdings: \n"; - print_r($kite->getHoldings()); - - // Retrieve quote and market depth for list of instruments. - echo "Quote: \n"; - print_r($kite->getQuote(["NSE:INFY", "NSE:SBIN"])); - - // Place order. - $order_id = $kite->placeOrder("regular", [ - "tradingsymbol" => "INFY", - "exchange" => "NSE", - "quantity" => 1, - "transaction_type" => "BUY", - "order_type" => "MARKET", - "product" => "NRML" - ])["order_id"]; - - echo "Order id is ".$order_id; - - // fetch order margin - $order_param = array(array("exchange" => "NSE", - "tradingsymbol" => "INFY", - "transaction_type" => $kite::TRANSACTION_TYPE_BUY, - "variety" => $kite::VARIETY_REGULAR, - "product" => $kite::PRODUCT_CNC, - "order_type" => $kite::ORDER_TYPE_MARKET, - "quantity" => 1 - ),); - print_r($kite->orderMargins($order_param)); + +require_once __DIR__ . '/vendor/autoload.php'; + +use KiteConnect\KiteConnect; + +// Initialise. +$kite = new KiteConnect("api_key"); + +// Assuming you have obtained the `request_token` +// after the auth flow redirect by redirecting the +// user to $kite->login_url() +try { + $user = $kite->generateSession("request_token", "secret_key"); + + echo "Authentication successful. \n"; + print_r($user); + + $kite->setAccessToken($user->access_token); +} catch (Exception $e) { + echo "Authentication failed: " . $e->getMessage(); + + throw $e; +} + +echo $user->user_id . " has logged in"; + +// Get the list of positions. +echo "Positions: \n"; +print_r($kite->getPositions()); + +// Get the list of holdings. +echo "Holdings: \n"; +print_r($kite->getHoldings()); + +// Retrieve quote and market depth for list of instruments. +echo "Quote: \n"; +print_r($kite->getQuote(["NSE:INFY", "NSE:SBIN"])); + +// Place order. +$order = $kite->placeOrder("regular", [ + "tradingsymbol" => "INFY", + "exchange" => "NSE", + "quantity" => 1, + "transaction_type" => "BUY", + "order_type" => "MARKET", + "product" => "CNC", +]); + +echo "Order id is " . $order->order_id; + +// fetch order margin +$order_param = [["exchange" => "NSE", + "tradingsymbol" => "INFY", + "transaction_type" => $kite::TRANSACTION_TYPE_BUY, + "variety" => $kite::VARIETY_REGULAR, + "product" => $kite::PRODUCT_CNC, + "order_type" => $kite::ORDER_TYPE_MARKET, + "quantity" => 1, +],]; + +print_r($kite->orderMargins($order_param)); + +$place_GTT = $kite->placeGTT([ + "trigger_type" => $kite::GTT_TYPE_SINGLE, + "tradingsymbol" => "TATAMOTORS", + "exchange" => "NSE", + "trigger_values" => array(310), + "last_price" => 315, + "orders" => array([ + "transaction_type" => $kite::TRANSACTION_TYPE_BUY, + "quantity" => 1, + "product" => $kite::PRODUCT_CNC, + "order_type" => $kite::ORDER_TYPE_LIMIT, + "price" => 314 + ]) +]); +echo "Trigger id is ".$place_GTT->trigger_id; + ?> diff --git a/kiteconnect.php b/kiteconnect.php deleted file mode 100644 index 180b5c5..0000000 --- a/kiteconnect.php +++ /dev/null @@ -1,1450 +0,0 @@ - -login_url() - try { - $user = $kite->generateSession("request_token_obtained", "your_api_secret"); - - echo "Authentication successful. \n"; - print_r($user); - - $kite->setAccessToken($user->access_token); - } catch(Exception $e) { - echo "Authentication failed: ".$e->getMessage(); - throw $e; - } - - echo $user->user_id." has logged in"; - - // Get the list of positions. - echo "Positions: \n"; - print_r($kite->getPositions()); - - // Place order. - $o = $kite->placeOrder("regular", [ - "tradingsymbol" => "INFY", - "exchange" => "NSE", - "quantity" => 1, - "transaction_type" => "BUY", - "order_type" => "MARKET", - "product" => "NRML" - ]); - - echo "Order id is ".$o->order_id; -?> - - -A typical web application -------------------------- -In a typical web application where a new instance of -views, controllers etc. are created per incoming HTTP -request, you will need to initialise a new instance of -Kite client per request as well. This is because each -individual instance represents a single user that's -authenticated, unlike an **admin** API where you may -use one instance to manage many users. - -Hence, in your web application, typically: - -- You will initialise an instance of the Kite client -- Redirect the user to the `login_url()` -- At the redirect url endpoint, obtain the -`request_token` from the query parameters -- Initialise a new instance of Kite client, -use `request_access_token()` to obtain the `access_token` -along with authenticated user data -- Store this response in a session and use the -stored `access_token` and initialise instances -of Kite client for subsequent API calls. - -Exceptions ----------- -Kite Connect client saves you the hassle of detecting API errors -by looking at HTTP codes or JSON error responses. Instead, -it raises aptly named **[exceptions](exceptions.m.html)** that you can catch. -*/ - -class KiteConnect { - // Default root API endpoint. It's possible to - // override this by passing the `root` parameter during initialisation. - private $_root = "https://api.kite.trade"; - private static $_login = "https://kite.trade/connect/login"; - private static $_date_fields = ["order_timestamp", "exchange_timestamp", "created", "last_instalment", "fill_timestamp", "timestamp", "last_trade_time"]; - const _version = "3.2.0"; - - // API route map. - private $_routes = [ - "api.token" => "/session/token", - "api.token.invalidate" => "/session/token", - "api.token.renew" => "/session/refresh_token", - "user.profile" => "/user/profile", - "user.margins" => "/user/margins", - "user.margins.segment" => "/user/margins/{segment}", - - "orders" => "/orders", - "trades" => "/trades", - - "order.info" => "/orders/{order_id}", - "order.place" => "/orders/{variety}", - "order.modify" => "/orders/{variety}/{order_id}", - "order.cancel" => "/orders/{variety}/{order_id}", - "order.trades" => "/orders/{order_id}/trades", - "order.margins" => "/margins/orders", - - "portfolio.positions" => "/portfolio/positions", - "portfolio.holdings" => "/portfolio/holdings", - "portfolio.positions.convert" => "/portfolio/positions", - - # MF api endpoints - "mf.orders" => "/mf/orders", - "mf.order.info" => "/mf/orders/{order_id}", - "mf.order.place" => "/mf/orders", - "mf.order.cancel" => "/mf/orders/{order_id}", - - "mf.sips" => "/mf/sips", - "mf.sip.info" => "/mf/sips/{sip_id}", - "mf.sip.place" => "/mf/sips", - "mf.sip.modify" => "/mf/sips/{sip_id}", - "mf.sip.cancel" => "/mf/sips/{sip_id}", - - "mf.holdings" => "/mf/holdings", - "mf.instruments" => "/mf/instruments", - - "market.instruments.all" => "/instruments", - "market.instruments" => "/instruments/{exchange}", - "market.margins" => "/margins/{segment}", - "market.historical" => "/instruments/historical/{instrument_token}/{interval}", - "market.trigger_range" => "/instruments/trigger_range/{transaction_type}", - - "market.quote" => "/quote", - "market.quote.ohlc" => "/quote/ohlc", - "market.quote.ltp" => "/quote/ltp", - - "gtt.triggers" => "/gtt/triggers", - "gtt.trigger_info" => "/gtt/triggers/{trigger_id}", - "gtt.place" => "/gtt/triggers", - "gtt.modify" => "/gtt/triggers/{trigger_id}", - "gtt.delete" => "/gtt/triggers/{trigger_id}" - ]; - - - // Instance variables. - public $timeout = 7; - public $api_key = null; - public $access_token = null; - public $debug = null; - public $session_hook = null; - public $micro_cache = true; - - // Constants - // Products - const PRODUCT_MIS = "MIS"; - const PRODUCT_CNC = "CNC"; - const PRODUCT_NRML = "NRML"; - const PRODUCT_CO = "CO"; - const PRODUCT_BO = "BO"; - - // Order types - const ORDER_TYPE_MARKET = "MARKET"; - const ORDER_TYPE_LIMIT = "LIMIT"; - const ORDER_TYPE_SLM = "SL-M"; - const ORDER_TYPE_SL = "SL"; - - // Varities - const VARIETY_REGULAR = "regular"; - const VARIETY_BO = "bo"; - const VARIETY_CO = "co"; - const VARIETY_AMO = "amo"; - - // Transaction type - const TRANSACTION_TYPE_BUY = "BUY"; - const TRANSACTION_TYPE_SELL = "SELL"; - - // Validity - const VALIDITY_DAY = "DAY"; - const VALIDITY_IOC = "IOC"; - - // Margins segments - const MARGIN_EQUITY = "equity"; - const MARGIN_COMMODITY = "commodity"; - - const STATUS_CANCELLED = "CANCELLED"; - const STATUS_REJECTED = "REJECTED"; - const STATUS_COMPLETE = "COMPLETE"; - - // GTT Types - const GTT_TYPE_OCO = "two-leg"; - const GTT_TYPE_SINGLE = "single"; - - // GTT Statuses - const GTT_STATUS_ACTIVE = "active"; - const GTT_STATUS_TRIGGERED = "triggered"; - const GTT_STATUS_DISABLED = "disabled"; - const GTT_STATUS_EXPIRED = "expired"; - const GTT_STATUS_CANCELLED = "cancelled"; - const GTT_STATUS_REJECTED = "rejected"; - const GTT_STATUS_DELETED = "deleted"; - - /** - * Initialise a new Kite Connect client instance. - * - * @param string $api_key The Kite Connect API key issued to you. - * @param string $access_token The token obtained after the login flow in exchange for the `request_token`. - * Pre-login, this will default to None, - * but once you have obtained it, you should - * persist it in a database or session to pass - * to the Kite Connect class initialisation for subsequent requests - * @param string $root The Kite Connect API end point root. Unless you explicitly - * want to send API requests to a non-default endpoint, this - * should be left as null. - * @param int $debug If set to True, requests and responses will be `echo`ed. - * @param int $timeout The the time (seconds) for which the API client will wait for - * a request to complete before it fails. - * @return void - */ - public function __construct($api_key, $access_token = null, $root = null, $debug = false, $timeout = 7) { - $this->api_key = $api_key; - $this->access_token = $access_token; - $this->debug = $debug; - $this->session_hook = null; - $this->timeout = $timeout; - - if($root) { - $this->_root = $root; - } - } - - /** - * Set a callback hook for session (TokenError -- timeout, expiry etc.) errors. - * - * An `access_token` (login session) can become invalid for a number of - * reasons, but it doesn't make sense for the client to - * try and catch it during every API call. - * - * A callback method that handles session errors - * can be set here and when the client encounters - * a token error at any point, it'll be called. - * This callback, for instance, can log the user out of the UI, - * clear session cookies, or initiate a fresh login. - * - * @param function $method The callback function that should be - * called in case of a TokenError error. - * @return void - */ - public function setSessionExpiryHook($method) { - $this->session_hook = $method; - } - - /** - * Set the `access_token` received after a successful authentication. - * - * @param string $access_token The `access_token` received after a successful - * authentication token exchange. - * @return void - */ - public function setAccessToken($access_token) { - $this->access_token = $access_token; - } - - /** - * Get the remote login url to which a user should be redirected - * to initiate the login flow. - * - * @return string Login url - */ - public function getLoginURL() { - return sprintf("%s?api_key=%s&v=3", self::$_login, $this->api_key); - } - - /** - * Do the token exchange with the `request_token` obtained after the login flow, - * and retrieve the `access_token` required for all subsequent requests. The - * response contains not just the `access_token`, but metadata for - * the user who has authenticated. - * - * @param string $request_token Token obtained from the GET params after a successful login redirect - * @param string $api_secret The API secret issued with the API key. - * @return array - */ - public function generateSession($request_token, $api_secret) { - $checksum = hash("sha256", $this->api_key.$request_token.$api_secret); - - $resp = $this->_post("api.token", [ - "api_key" => $this->api_key, - "request_token" => $request_token, - "checksum" => $checksum - ]); - - if($resp->access_token) { - $this->setAccessToken($resp->access_token); - } - - if($resp->login_time) { - $resp->login_time = new DateTime($resp->login_time, new DateTimeZone("Asia/Kolkata")); - } - - return $resp; - } - - /** - * Kill the session by invalidating the access token. - * - * @param string|null $access_token (Optional) `access_token` to invalidate. Default is the active `access_token`. - * @return none - */ - public function invalidateAccessToken($access_token = null) { - if(!$access_token) { - $access_token = $this->access_token; - } - - return $this->_delete("api.token.invalidate", [ - "access_token" => $access_token, - "api_key" => $this->api_key - ]); - } - - /** - * Renew access token by active refresh token. - * Renewed access token is implicitly set. - * - * @param string $refresh_token Token obtained from previous successful login. - * @param string $api_secret The API secret issued with the API key. - * @return array - */ - public function renewAccessToken($refresh_token, $api_secret) { - $checksum = hash("sha256", $this->api_key.$refresh_token.$api_secret); - - $resp = $this->_post("api.token.renew", [ - "api_key" => $this->api_key, - "refresh_token" => $refresh_token, - "checksum" => $checksum - ]); - - if(!empty($resp->access_token)) { - $this->setAccessToken($resp->access_token); - } - - return $resp; - } - - /** - * Invalidate refresh token. - * - * @param string $refresh_token Refresh token to invalidate. - * @return none - */ - public function invalidateRefreshToken($refresh_token) { - return $this->_delete("api.token.invalidate", [ - "refresh_token" => $refresh_token, - "api_key" => $this->api_key - ]); - } - - /** - * Get user profile. - * - * @return array - */ - public function getProfile() { - return $this->_get("user.profile"); - } - - /** - * Get account balance and cash margin details for a particular segment. - * - * @param string|null $segment (Optional) trading segment (eg: equity or commodity) - * @return array - */ - public function getMargins($segment = null) { - if (!$segment) { - return $this->_get("user.margins"); - } - - return $this->_get("user.margins.segment", ["segment" => $segment]); - } - - /** - * Place an order. - * - * @param string $variety "variety" Order variety (ex. bo, co, amo, regular). - * @param array $params [Order parameters](https://kite.trade/docs/connect/v3/orders/#regular-order-parameters) - * $params string "exchange" Exchange in which instrument is listed (NSE, BSE, NFO, BFO, CDS, MCX). - * $params string "tradingsymbol" Tradingsymbol of the instrument (ex. RELIANCE, INFY). - * $params string "transaction_type" Transaction type (BUY or SELL). - * $params string "product" Product code (NRML, MIS, CNC). - * $params string "order_type" Order type (SL, SL-M, LIMIT, MARKET). - * $params int "quantity" Order quantity - * $params int|null "disclosed_quantity" (Optional) Disclosed quantity - * $params float|null "price" (Optional) Order Price - * $params float|null "trigger_price" (Optional) Trigger price - * $params float|null "squareoff" (Mandatory only for bracker orders) Square off value - * $params float|null "stoploss" (Mandatory only for bracker orders) Stoploss value - * $params float|null "trailing_stoploss" (Optional) Trailing stoploss value (only for bracket orders) - * $params float|null "tag" (Optional) Order tag - * $params string|null "validity" (Optional) Order validity (DAY, IOC). - * @return string - */ - public function placeOrder($variety, $params) { - $params["variety"] = $variety; - return $this->_post("order.place", $params); - } - - /** - * Modify an open order. - * - * @param string $variety "variety" Order variety (ex. bo, co, amo, regular). - * @param string $order_id "order_id" Order id. - * @param array $params [Order modify parameters](https://kite.trade/docs/connect/v3/orders/#regular-order-parameters_1). - * $params string "parent_order_id" (Optional) Parent order id if its a multi legged order. - * $params string "order_type" (Optional) Order type (SL, SL-M, MARKET) - * $params int "quantity" (Optional) Order quantity - * $params int|null "disclosed_quantity" (Optional) Disclosed quantity - * $params float|null "price" (Optional) Order Price - * $params float|null "trigger_price" (Optional) Trigger price - * $params string|null "validity" (Optional) Order validity (DAY, IOC). - * - * @return void - */ - public function modifyOrder($variety, $order_id, $params) { - $params["variety"] = $variety; - $params["order_id"] = $order_id; - return $this->_put("order.modify", $params); - } - - /** - * Cancel an open order. - * - * @param string $variety "variety" Order variety (ex. bo, co, amo, regular). - * @param string $order_id "order_id" Order id. - * @param array $params [Order cancel parameters](https://kite.trade/docs/connect/v3/orders/#cancelling-orders) - * $params string "parent_order_id" (Optional) Parent order id if its a multi legged order. - * - * @return void - */ - public function cancelOrder($variety, $order_id, $params=null) { - if (!$params) { - $params = []; - } - - $params["variety"] = $variety; - $params["order_id"] = $order_id; - - return $this->_delete("order.cancel", $params); - } - - /** - * Exit a BO or CO. - * - * @param string $variety "variety" Order variety (ex. bo, co, amo, regular). - * @param string $order_id "order_id" Order id. - * @param array $params [Order cancel parameters](https://kite.trade/docs/connect/v3/orders/#cancelling-orders) - * $params string "parent_order_id" (Optional) Parent order id if its a multi legged order. - * - * @return void - */ - public function exitOrder($variety, $order_id, $params) { - return $this->cancelOrder($variety, $order_id, $params); - } - - /** - * Get the list of all orders placed for the day. - * @return array - */ - public function getOrders() { - return $this->_format_response_array($this->_get("orders")); - } - - /** - * Get history of the individual order. - * @param string $order_id ID of the order (optional) whose trades - * are to be retrieved. If no `order_id` is - * specified, all trades for the day are returned. - * @return array - */ - public function getOrderHistory($order_id) { - return $this->_format_response_array($this->_get("order.info", ["order_id" => $order_id])); - } - - /** - * Fetch order margin - * - * @param array $params Order params to fetch margin detail - * $params string "exchange" Name of the exchange(eg. NSE, BSE, NFO, CDS, MCX) - * $params string "tradingsymbol" Trading symbol of the instrument - * $params string "transaction_type" eg. BUY, SELL - * $params string "variety" Order variety (regular, amo, bo, co etc.) - * $params string "product" Margin product to use for the order - * $params string "order_type" Order type (MARKET, LIMIT etc.) - * $params int "quantity" Quantity of the order - * $params float|null "price" Price at which the order is going to be placed (LIMIT orders) - * $params float|null "trigger_price" Trigger price (for SL, SL-M, CO orders) - * @return array - */ - public function orderMargins($params) { - return $this->_post("order.margins", json_encode($params), 'Content-type: application/json'); - } - - /** - * Retrieve the list of trades executed. - * @return array - */ - public function getTrades() { - return $this->_format_response_array($this->_get("trades")); - } - - /** - * Retrieve the list of trades executed for a particular order. - * - * An order can be executed in tranches based on market conditions. - * These trades are individually recorded under an order. - * - * @param string $order_id ID of the order (optional) whose trades - * are to be retrieved. If no `order_id` is - * specified, all trades for the day are returned. - * @return array - */ - public function getOrderTrades($order_id) { - return $this->_format_response_array($this->_get("order.trades", ["order_id" => $order_id])); - } - - /** - * Retrieve the list of positions - * - * @return array - */ - public function getPositions() { - return $this->_get("portfolio.positions"); - } - - /** - * Retrieve the list of equity holdings. - * - * @return array - */ - public function getHoldings() { - return $this->_get("portfolio.holdings"); - } - - /** - * Modify an open position's product type. - * @param array $params [Parameters](https://kite.trade/docs/connect/v3/portfolio/#position-conversion) describing the open position to be modified. - * $param string "exchange" Exchange in which instrument is listed (NSE, BSE, NFO, BFO, CDS, MCX). - * $param string "tradingsymbol" Tradingsymbol of the instrument (ex. RELIANCE, INFY). - * $param string "transaction_type" Transaction type (BUY or SELL). - * $param string "position_type" Position type (overnight, day). - * $param string "quantity" Position quantity - * $param string "old_product" Current product code (NRML, MIS, CNC). - * $param string "new_product" New Product code (NRML, MIS, CNC). - * @return bool - */ - public function convertPosition($params) { - return $this->_put("portfolio.positions.convert", $params); - } - - /** - * Retrieve the list of market instruments available to trade. - * - * Note that the results could be large, several hundred KBs in size, - * with tens of thousands of entries in the array. The actual response - * from the API is in the CSV format, but this function parses the CSV - * into an array of Objects where an individual object looks like: - *
Class Object - * ( - * [instrument_token] => 128031748 - * [exchange_token] => 500124 - * [tradingsymbol] => DRREDDY* - * [name] => DR.REDDYS LABORATORIES - * [last_price] => 0 - * [expiry] => - * [strike] => 0 - * [tick_size] => 0.05 - * [lot_size] => 1 - * [instrument_type] => EQ - * [segment] => BSE - * [exchange] => BSE - * ) - *- * - * @param string|null $exchange (Optional) Exchange. - * @return array - */ - public function getInstruments($exchange = null) { - if($exchange) { - $params = ["exchange" => $exchange]; - - return $this->_parseInstrumentsCSV($this->_get("market.instruments", $params)); - } else { - return $this->_parseInstrumentsCSV($this->_get("market.instruments.all")); - } - } - - /** - * Retrieve quote and market depth for list of instruments. - * - * @param array instruments is a list of instruments, Instrument are in the format of `tradingsymbol:exchange`. - * For example NSE:INFY - * @return array - */ - public function getQuote($instruments) { - return $this->_format_response_array($this->_get("market.quote", ["i" => $instruments])); - } - - /** - * Retrieve OHLC for list of instruments. - * - * @param array instruments is a list of instruments, Instrument are in the format of `tradingsymbol:exchange`. - * For example NSE:INFY - * @return array - */ - public function getOHLC($instruments) { - return $this->_get("market.quote.ohlc", ["i" => $instruments]); - } - - /** - * Retrieve LTP for list of instruments. - * - * @param array instruments is a list of instruments, Instrument are in the format of `tradingsymbol:exchange`. - * For example NSE:INFY - * @return array - */ - public function getLTP($instruments) { - return $this->_get("market.quote.ltp", ["i" => $instruments]); - } - - - /** - * Retrieve historical data (candles) for an instrument. - * - * Although the actual response JSON from the API does not have field - * names such has 'open', 'high' etc., this functin call structures - * the data into an array of objects with field names. For example: - *
stdClass Object - * ( - * [date] => 2016-05-02T09:15:00+0530 - * [open] => 1442 - * [high] => 1446.45 - * [low] => 1416.15 - * [close] => 1420.55 - * [volume] => 205976 - * ) - *- * - * @param array $params - Historical data params - * $params string "instrument_token" Instrument identifier (retrieved from the instruments()) call. - * $params string|DateTime "from" From date (String in format of 'yyyy-mm-dd HH:MM:SS' or Date object). - * $params string|DateTime "to" To date (String in format of 'yyyy-mm-dd HH:MM:SS' or Date object). - * $params string "interval" candle interval (minute, day, 5 minute etc.) - * $params bool "continuous" is a bool flag to get continuous data for futures and options instruments. Defaults to false. - * @return array - */ - public function getHistoricalData($instrument_token, $interval, $from, $to, $continuous = false, $oi = false) { - $params = [ - "instrument_token" => $instrument_token, - "interval" => $interval, - "from" => $from, - "to" => $to, - "continuous" => $continuous, - "oi" => $oi - ]; - - if ($from instanceof DateTime) { - $params["from"] = $from->format("Y-m-d H:i:s"); - } - - if ($to instanceof DateTime) { - $params["to"] = $to->format("Y-m-d H:i:s"); - } - - if ($params["continuous"] == false) { - $params["continuous"] = 0; - } else { - $params["continuous"] = 1; - } - - if ($params["oi"] == false) { - $params["oi"] = 0; - } else { - $params["oi"] = 1; - } - - $data = $this->_get("market.historical", $params); - - $records = []; - foreach($data->candles as $j) { - $r = new stdclass; - $r->date = new DateTime($j[0], new DateTimeZone("Asia/Kolkata")); - $r->open = $j[1]; - $r->high = $j[2]; - $r->low = $j[3]; - $r->close = $j[4]; - $r->volume = $j[5]; - if (!empty($j[6])) { - $r->oi = $j[6]; - } - - $records[] = $r; - } - - return $records; - } - - /** - * Retrieve the buy/sell trigger range for Cover Orders. - * @param string $exchange Exchange - * @param string $tradingsymbol Tradingsymbol - * @param string $transaction_type Transaction type - * @return array - */ - public function getTriggerRange($transaction_type, $instruments) { - return $this->_get("market.trigger_range", - ["i" => $instruments, "transaction_type" => strtolower($transaction_type)]); - } - - /** - * Get the list of MF orders / order info for individual order. - * @param string|null $order_id (Optional) Order id. - * @return array - */ - public function getMFOrders($order_id=null) { - if ($order_id) { - return $this->_format_response($this->_get("mf.order.info", ["order_id" => $order_id])); - } - - return $this->_format_response_array($this->_get("mf.orders")); - } - - /** - * Get the list of MF holdings. - * @return array - */ - public function getMFHoldings() { - return $this->_get("mf.holdings"); - } - - /** - * Place an mutual fund order. - * - * @param array $params [Order parameters](https://kite.trade/docs/connect/v3/mf/#orders) - * $param string "tradingsymbol" Tradingsymbol (ISIN) of the fund. - * $param string "transaction_type" Transaction type (BUY or SELL). - * $param int|null "quantity" Quantity to SELL. Not applicable on BUYs. - * $param float|null "amount" (Optional) Amount worth of units to purchase. Not applicable on SELLs - * $param string|null "tag" (Optional) An optional tag to apply to an order to identify it (alphanumeric, max 8 chars) - * @return string - */ - public function placeMFOrder($params) { - return $this->_post("mf.order.place", $params); - } - - /** - * Cancel an mutual fund order. - * - * @param string $order_id Order id. - * @return string - */ - public function cancelMFOrder($order_id) { - return $this->_delete("mf.order.cancel", ["order_id" => $order_id]); - } - - /** - * Get the list of mutual fund SIP's or individual SIP info. - * @param string|null $sip_id (Optional) SIP id. - * @return array - */ - public function getMFSIPS($sip_id = null) { - if ($sip_id) { - return $this->_format_response($this->_get("mf.sip.info", ["sip_id" => $sip_id])); - } - - return $this->_format_response_array($this->_get("mf.sips")); - } - - /** - * Place an mutual fund order. - * - * @param array $params [Mutual fund SIP parameters](https://kite.trade/docs/connect/v3/mf/#sip-orders) - * $param string "tradingsymbol" Tradingsymbol (ISIN) of the fund. - * $param float "amount" Amount worth of units to purchase. Not applicable on SELLs - * $param int "instalments" Number of instalments to trigger. If set to -1, instalments are triggered at fixed intervals until the SIP is cancelled - * $param string "frequency" Order frequency. weekly, monthly, or quarterly. - * $param float|null "initial_amount" (Optional) Amount worth of units to purchase before the SIP starts. - * $param int|null "instalment_day" (Optional) If frequency is monthly, the day of the month (1, 5, 10, 15, 20, 25) to trigger the order on. - * $param string|null "tag" An optional (Optional) tag to apply to an order to identify it (alphanumeric, max 8 chars) - * @return string - */ - public function placeMFSIP($params) { - return $this->_post("mf.sip.place", $params); - } - - /** - * Place an mutual fund order. - * - * @param string Mutual fund SIP ID. - * @param array $params [Mutual fund SIP modify parameters](https://kite.trade/docs/connect/v1/#orders30) - * $param float "amount" Amount worth of units to purchase. Not applicable on SELLs - * $param int|null "instalments" (Optional) Number of instalments to trigger. If set to -1, instalments are triggered at fixed intervals until the SIP is cancelled - * $param string|null "frequency" (Optional) Order frequency. weekly, monthly, or quarterly. - * $param int|null "instalment_day" (Optional) If frequency is monthly, the day of the month (1, 5, 10, 15, 20, 25) to trigger the order on. - * $param string|null "status" (Optional) Pause or unpause an SIP (active or paused). - * @return string - */ - public function modifyMFSIP($sip_id, $params) { - $params["sip_id"] = $sip_id; - return $this->_put("mf.sip.modify", $params); - } - - /** - * Cancel an mutual fund order. - * - * @param string $sip_id SIP id. - * @return string - */ - public function cancelMFSIP($sip_id) { - return $this->_delete("mf.sip.cancel", ["sip_id" => $sip_id]); - } - - /** - * Get list of mutual fund instruments. - * - * @return array - */ - public function getMFInstruments() { - return $this->_parseMFInstrumentsCSV($this->_get("mf.instruments")); - } - - - /** - * Get the list of all orders placed for the day. - * @return array - */ - public function getGTTs() { - return $this->_format_response_array($this->_get("gtt.triggers")); - } - - /** - * Get detail of individual GTT order. - * @param string $trigger_id "trigger_id" Trigger ID - * @return array - */ - public function getGTT($trigger_id) { - return $this->_format_response($this->_get("gtt.trigger_info", ["trigger_id" => $trigger_id])); - } - - /** - * Delete an GTT order - * @param string $trigger_id "trigger_id" Trigger ID - * @return void - */ - public function deleteGTT($trigger_id) { - return $this->_delete("gtt.delete", ["trigger_id" => $trigger_id]); - } - - private function getGTTPayload($params) { - if ($params["trigger_type"] == self::GTT_TYPE_OCO && count($params["trigger_values"]) != 2) { - throw new DataException("Invalid `trigger_values` for `OCO` order type"); - } - if ($params["trigger_type"] == self::GTT_TYPE_SINGLE && count($params["trigger_values"]) != 1) { - throw new DataException("Invalid `trigger_values` for `single` order type"); - } - $condition = [ - "exchange" => $params["exchange"], - "tradingsymbol" => $params["tradingsymbol"], - "trigger_values" => $params["trigger_values"], - "last_price" => (float)$params["last_price"] - ]; - $orders = array(); - foreach ($params["orders"] as &$o) { - array_push($orders, [ - "transaction_type" => $o["transaction_type"], - "order_type" => $o["order_type"], - "product" => $o["product"], - "quantity" => (int)$o["quantity"], - "price" => (float)($o["price"]), - "exchange" => $params["exchange"], - "tradingsymbol" => $params["tradingsymbol"] - ]); - } - return [ - "condition" => $condition, - "orders" => $orders - ]; - } - - /** - * Place a GTT. Check [GTT documentation](https://kite.trade/docs/connect/v3/gtt/#placing-orders) for details. - *
- * $params = [
- * // GTT type, its either `$kite::GTT_TYPE_OCO` or `$kite::GTT_TYPE_SINGLE`.
- * "trigger_type" => $kite::GTT_TYPE_OCO,
- * // Tradingsymbol of the instrument (ex. RELIANCE, INFY).
- * "tradingsymbol" => "SBIN",
- * // Exchange in which instrument is listed (NSE, BSE, NFO, BFO, CDS, MCX).
- * "exchange" => "NSE",
- * // List of trigger values, number of items depends on trigger type.
- * "trigger_values" => array(300, 400),
- * // Price at which trigger is created. This is usually the last price of the instrument.
- * "last_price" => 318,
- * // List of orders. Check [order params](https://kite.trade/docs/connect/v3/orders/#regular-order-parameters) for all available params.
- * "orders" => array([
- * "transaction_type" => $kite::TRANSACTION_TYPE_SELL,
- * "quantity" => 1,
- * "product" => $kite::PRODUCT_CNC,
- * "order_type" => $kite::ORDER_TYPE_LIMIT,
- * "price" => 300
- * ], [
- * "transaction_type" => $kite::TRANSACTION_TYPE_SELL,
- * "quantity" => 1,
- * "product" => $kite::PRODUCT_CNC,
- * "order_type" => $kite::ORDER_TYPE_LIMIT,
- * "price" => 400
- * ])
- * ]
- *
- *
- * @param array $params GTT Params. Check above for required fields.
- */
- public function placeGTT($params) {
- $payload = $this->getGTTPayload($params);
- return $this->_post("gtt.place", [
- "condition" => json_encode($payload["condition"]),
- "orders" => json_encode($payload["orders"]),
- "type" => $params["trigger_type"]
- ]);
- }
-
- /**
- * Modify GTT. Check [GTT documentation](https://kite.trade/docs/connect/v3/gtt/#modify-order) for details.
- *
- * $params = [
- * // GTT type, its either `$kite::GTT_TYPE_OCO` or `$kite::GTT_TYPE_SINGLE`.
- * "trigger_type" => $kite::GTT_TYPE_OCO,
- * // Tradingsymbol of the instrument (ex. RELIANCE, INFY).
- * "tradingsymbol" => "SBIN",
- * // Exchange in which instrument is listed (NSE, BSE, NFO, BFO, CDS, MCX).
- * "exchange" => "NSE",
- * // List of trigger values, number of items depends on trigger type.
- * "trigger_values" => array(300, 400),
- * // Price at which trigger is created. This is usually the last price of the instrument.
- * "last_price" => 318,
- * // List of orders. Check [order params](https://kite.trade/docs/connect/v3/orders/#regular-order-parameters) for all available params.
- * "orders" => array([
- * "transaction_type" => $kite::TRANSACTION_TYPE_SELL,
- * "quantity" => 1,
- * "product" => $kite::PRODUCT_CNC,
- * "order_type" => $kite::ORDER_TYPE_LIMIT,
- * "price" => 300
- * ], [
- * "transaction_type" => $kite::TRANSACTION_TYPE_SELL,
- * "quantity" => 1,
- * "product" => $kite::PRODUCT_CNC,
- * "order_type" => $kite::ORDER_TYPE_LIMIT,
- * "price" => 400
- * ])
- * ]
- *
- * @param int $trigger_id GTT Trigger ID
- * @param array $params GTT Params. Check above for required fields.
- */
- public function modifyGTT($trigger_id, $params) {
- $payload = $this->getGTTPayload($params);
- return $this->_put("gtt.modify", [
- "condition" => json_encode($payload["condition"]),
- "orders" => json_encode($payload["orders"]),
- "type" => $params["trigger_type"],
- "trigger_id" => $trigger_id
- ]);
- }
-
- /**
- * Format response array, For example datetime string to DateTime object
- */
- private function _format_response($data) {
- foreach(self::$_date_fields as $field) {
- if (isset($data->$field) && strlen($data->$field) == 19) {
- $data->$field = new DateTime($data->$field, new DateTimeZone("Asia/Kolkata"));
- }
- }
-
- return $data;
- }
-
- /**
- * Format array of responses
- */
- private function _format_response_array($data) {
- $results = [];
- foreach ($data as $k => $item) {
- $results[$k] = $this->_format_response($item);
- }
-
- return $results;
- }
-
- /**
- * Alias for sending a GET request.
- *
- * @param string $route Route name mapped in self::$_routes.
- * @param array|null $params Request parameters.
- * @return mixed Array or object (deserialised JSON).
- */
- private function _get($route, $params=null, $header_content=null) {
- return $this->_request($route, "GET", $params, $header_content);
- }
-
- /**
- * Alias for sending a GET request.
- *
- * @param string $route Route name mapped in self::$_routes.
- * @param array|null $params Request parameters.
- * @return mixed Array or object (deserialised JSON).
- */
- private function _post($route, $params=null, $header_content=null) {
- return $this->_request($route, "POST", $params, $header_content);
- }
-
- /**
- * Alias for sending a PUT request.
- *
- * @param string $route Route name mapped in self::$_routes.
- * @param array|null $params Request parameters.
- * @return mixed Array or object (deserialised JSON).
- */
- private function _put($route, $params=null, $header_content=null) {
- return $this->_request($route, "PUT", $params, $header_content);
- }
-
- /**
- * Alias for sending a GET request.
- *
- * @param string $route Route name mapped in self::$_routes.
- * @param array|null $params Request parameters.
- * @return mixed Array or object (deserialised JSON).
- */
- private function _delete($route, $params=null, $header_content=null) {
- return $this->_request($route, "DELETE", $params, $header_content);
- }
-
- /**
- * Make an HTTP request.
- *
- * @param string $route Route name mapped in self::$_routes.
- * @param string $method The HTTP method to send (GET, POST, PUT, DELETE).
- * @param array|null $params Request parameters.
- * @return mixed Array or object (deserialised JSON).
- */
- private function _request($route, $method, $params, $header_content) {
- $uri = $this->_routes[$route];
-
- // 'RESTful' URLs.
- if(strpos($uri, "{") !== false) {
- foreach($params as $k=>$v) {
- $uri = str_replace("{" . $k . "}", $v, $uri);
- }
- }
-
- $url = $this->_root.$uri;
-
- if($this->debug) {
- print("Request: " . $method . " " . $url . "\n");
- var_dump($params);
- }
-
- // Set the header content type, if not sent set it to default
- if ($header_content){
- $content_type = $header_content;
- } else {
- // default header content type of urlencoded
- $content_type = "Content-type: application/x-www-form-urlencoded";
- }
- // Prepare the payload
- $request_headers[] = [$content_type,
- "User-Agent: phpkiteconnect/".self::_version,
- "X-Kite-Version: 3"];
-
- if ($this->api_key && $this->access_token) {
- $request_headers[] = "Authorization: token " . $this->api_key . ":" . $this->access_token;
- }
- // Make the HTTP request.
- if(function_exists("curl_init")) {
- $resp = $this->_curl($url, $method, $request_headers, $params);
- } else {
- trigger_error("The php curl module is not installed. Please isntall it for better performance.", E_USER_WARNING);
- $resp = $this->_http_socket($url, $method, $request_headers, $params);
- }
- $headers = $resp["headers"];
- $result = $resp["body"];
-
- if($this->debug) {
- print("Response :" . $result . "\n");
- }
- if(empty($headers["content-type"])) {
- throw new DataException("Unknown content-type in response");
- } else if(strpos($headers["content-type"], "application/json") !== false) {
- $json = @json_decode($result);
- if(!$json) {
- throw new DataException("Couldn't parse JSON response");
- }
-
- // Token error.
- if($json->status == "error") {
- if($headers["status_code"] == 403) {
- if($this->session_hook) {
- $this->session_hook();
- return;
- }
- }
- // Check if the exception class is defined.
- if(class_exists($json->error_type)) {
- throw new $json->error_type($json->message, $headers["status_code"]);
- } else {
- throw new GeneralException($json->message, $headers["status_code"]);
- }
- }
-
- return $json->data;
- } else if(strpos($headers["content-type"], "text/csv") !== false) {
- return $result;
- } else {
- throw new DataException("Invalid response: ".$result, $headers["status_code"]);
- }
- }
-
- /**
- * Make an HTTP request using the PHP socket functions.
- *
- * @param string $url The full URL to retrieve
- * @param string $method The HTTP method to send (GET, POST, PUT, DELETE).
- * @param array|null $headers Array of HTTP request headers to send.
- * @param array|null $params Array of key=>value request parameters.
- * @return array Returns an array with response "headers" and "body".
- */
- private function _http_socket($url, $method, $headers, $params=null) {
- // Prepare the payload.
- $payload = http_build_query($params ? $params : []);
- $payload = preg_replace("/%5B(\d+?)%5D/", "", $payload);
-
- $request_headers = "";
- if($headers && count($headers) > 0) {
- $request_headers = implode("\r\n", $headers);
- }
-
- $options = [
- "method" => $method,
- "content" => $payload,
- "ignore_errors" => true,
- "header" => $request_headers
- ];
-
- if($method == "GET" || $method == "DELETE") {
- $url .= "?" . $payload;
- }
-
- $context = stream_context_create(["http" => $options]);
- $result = @file_get_contents($url, false, $context);
-
- // Request failed due to a network error.
- if(!$result) {
- $error = error_get_last();
- throw new NetworkException($error["message"]);
- }
-
- $response_headers = $this->_parseHeaders($http_response_header);
-
- // Content is gzipped. Uncompress.
- if(isset($response_headers["content-encoding"]) && stristr($response_headers["content-encoding"], "gzip")) {
- $result = gzdecode($result);
- }
-
- return ["headers" => $response_headers, "body" => $result];
- }
-
- /**
- * Make an HTTP request using the PHP curl library.
- *
- * @param string $url The full URL to retrieve
- * @param string $method The HTTP method to send (GET, POST, PUT, DELETE).
- * @param array|null $headers Array of HTTP request headers to send.
- * @param array|null $params Array of key=>value request parameters.
- * @return array Returns an array with response "headers" and "body".
- */
- private function _curl($url, $method, $headers, $params=null) {
- $ch = curl_init();
-
- curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
- curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
- curl_setopt($ch, CURLOPT_ENCODING , "gzip");
- curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
-
- if($headers && is_array($headers) && count($headers) > 0) {
- curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
- }
-
- // Prepare the payload.
- $payload = null;
- if($payload = http_build_query($params && is_array($params) ? $params : [])) {
- $payload = preg_replace("/%5B(\d+?)%5D/", "", $payload);
- } else if(json_decode($params)){
- // send json param payload
- $payload = $params;
- }
-
- if($method == "POST" || $method == "PUT") {
- curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
- } else if($method == "GET" || $method == "DELETE") {
- $url .= "?" . $payload;
- }
-
- // Request URL.
- curl_setopt($ch, CURLOPT_URL, $url);
-
- // Routine to collect the response headers.
- $response_headers = [];
- curl_setopt($ch, CURLOPT_HEADERFUNCTION, function($curl, $header) use (&$response_headers) {
- $len = strlen($header);
- $header = explode(':', $header, 2);
- if (count($header) < 2) {
- return $len;
- }
-
- $name = strtolower(trim($header[0]));
- if (!array_key_exists($name, $response_headers)) {
- $response_headers[$name] = trim($header[1]);
- } else {
- $response_headers[$name] = trim($header[1]);
- }
-
- return $len;
- });
-
- $result = curl_exec($ch);
-
- // Request error.
- if($error = curl_error($ch)) {
- throw new NetworkException($error);
- }
-
- $response_headers["status_code"] = intval(curl_getinfo($ch, CURLINFO_HTTP_CODE));
-
- return ["headers" => $response_headers, "body" => $result];
- }
-
- /**
- * Parse a CSV dump into an array of objects.
- * @param string $csv Complete CSV dump.
- * @return array
- */
- private function _parseInstrumentsCSV($csv) {
- $lines = explode("\n", $csv);
-
- $records = [];
- $head = [];
- for($n=0; $nClass Object + * ( + * [instrument_token] => 128031748 + * [exchange_token] => 500124 + * [tradingsymbol] => DRREDDY* + * [name] => DR.REDDYS LABORATORIES + * [last_price] => 0 + * [expiry] => + * [strike] => 0 + * [tick_size] => 0.05 + * [lot_size] => 1 + * [instrument_type] => EQ + * [segment] => BSE + * [exchange] => BSE + * ) + *+ * + * @param string|null $exchange (Optional) Exchange. + * @return array + * @throws DataException + * @throws GeneralException + * @throws InputException + * @throws NetworkException + * @throws OrderException + * @throws PermissionException + * @throws TokenException + */ + public function getInstruments(?string $exchange = null): array + { + if ($exchange) { + $params = ["exchange" => $exchange]; + + return $this->parseInstrumentsToCSV($this->get("market.instruments", $params)); + } else { + return $this->parseInstrumentsToCSV($this->get("market.instruments.all")); + } + } + + /** + * Retrieve quote and market depth for list of instruments. + * + * @param array $instruments instruments is a list of instruments, Instrument are in the format of `tradingsymbol:exchange`. + * For example NSE:INFY + * @return array + * @throws DataException + * @throws GeneralException + * @throws InputException + * @throws NetworkException + * @throws OrderException + * @throws PermissionException + * @throws TokenException + */ + public function getQuote(array $instruments): array + { + return $this->formatResponseArray($this->get("market.quote", ["i" => $instruments])); + } + + /** + * Retrieve OHLC for list of instruments. + * + * @param array $instruments instruments is a list of instruments, Instrument are in the format of `tradingsymbol:exchange`. + * For example NSE:INFY + * @return mixed + * @throws DataException + * @throws GeneralException + * @throws InputException + * @throws NetworkException + * @throws OrderException + * @throws PermissionException + * @throws TokenException + */ + public function getOHLC(array $instruments): mixed + { + return $this->get("market.quote.ohlc", ["i" => $instruments]); + } + + /** + * Retrieve LTP for list of instruments. + * + * @param array $instruments instruments is a list of instruments, Instrument are in the format of `tradingsymbol:exchange`. + * For example NSE:INFY + * @return mixed + * @throws DataException + * @throws GeneralException + * @throws InputException + * @throws NetworkException + * @throws OrderException + * @throws PermissionException + * @throws TokenException + */ + public function getLTP(array $instruments): mixed + { + return $this->get("market.quote.ltp", ["i" => $instruments]); + } + + /** + * Retrieve historical data (candles) for an instrument. + * + * Although the actual response JSON from the API does not have field + * names such has 'open', 'high' etc., this functin call structures + * the data into an array of objects with field names. For example: + *
stdClass Object + * ( + * [date] => 2016-05-02T09:15:00+0530 + * [open] => 1442 + * [high] => 1446.45 + * [low] => 1416.15 + * [close] => 1420.55 + * [volume] => 205976 + * ) + *+ * + * + * @param string $instrument_token "instrument_token" Instrument identifier (retrieved from the instruments()) call. + * @param string $interval "interval" candle interval (minute, day, 5 minute etc.) + * @param string|DateTime $from "from" From date (String in format of 'yyyy-mm-dd HH:MM:SS' or Date object). + * @param string|DateTime $to "to" To date (String in format of 'yyyy-mm-dd HH:MM:SS' or Date object). + * @param bool $continuous "continuous" is a bool flag to get continuous data for futures and options instruments. Defaults to false. + * @param bool $oi + * @return array + * @throws Exception + */ + public function getHistoricalData( + string $instrument_token, + string $interval, + $from, + $to, + bool $continuous = false, + bool $oi = false + ): array { + $params = [ + "instrument_token" => $instrument_token, + "interval" => $interval, + "from" => $from, + "to" => $to, + "continuous" => $continuous, + "oi" => $oi, + ]; + + if ($from instanceof DateTime) { + $params["from"] = $from->format("Y-m-d H:i:s"); + } + + if ($to instanceof DateTime) { + $params["to"] = $to->format("Y-m-d H:i:s"); + } + + if ($params["continuous"] == false) { + $params["continuous"] = 0; + } else { + $params["continuous"] = 1; + } + + if ($params["oi"] == false) { + $params["oi"] = 0; + } else { + $params["oi"] = 1; + } + + $data = $this->get("market.historical", $params); + + $records = []; + foreach ($data->candles as $j) { + $r = new stdclass; + $r->date = new DateTime($j[0], new DateTimeZone("Asia/Kolkata")); + $r->open = $j[1]; + $r->high = $j[2]; + $r->low = $j[3]; + $r->close = $j[4]; + $r->volume = $j[5]; + if (! empty($j[6])) { + $r->oi = $j[6]; + } + + $records[] = $r; + } + + return $records; + } + + /** + * Retrieve the buy/sell trigger range for Cover Orders. + * + * @param string $transaction_type Transaction type + * @param mixed $instruments + * @return array + * @throws DataException + * @throws GeneralException + * @throws InputException + * @throws NetworkException + * @throws OrderException + * @throws PermissionException + * @throws TokenException + */ + public function getTriggerRange(string $transaction_type, $instruments): array + { + return $this->get( + "market.trigger_range", + ["i" => $instruments, "transaction_type" => strtolower($transaction_type)] + ); + } + + /** + * Get the list of MF orders / order info for individual order. + * @param string|null $orderId (Optional) Order id. + * @return mixed + * @throws DataException + * @throws GeneralException + * @throws InputException + * @throws NetworkException + * @throws OrderException + * @throws PermissionException + * @throws TokenException + */ + public function getMFOrders(?string $orderId = null): mixed + { + if ($orderId) { + return $this->formatResponse($this->get("mf.order.info", ["order_id" => $orderId])); + } + + return $this->formatResponseArray($this->get("mf.orders")); + } + + /** + * Get the list of MF holdings. + * @return array + * @throws DataException + * @throws GeneralException + * @throws InputException + * @throws NetworkException + * @throws OrderException + * @throws PermissionException + * @throws TokenException + */ + public function getMFHoldings(): array + { + return $this->get("mf.holdings"); + } + + /** + * Place an mutual fund order. + * + * @param array $params [Order parameters](https://kite.trade/docs/connect/v3/mf/#orders) + * $param string "tradingsymbol" Tradingsymbol (ISIN) of the fund. + * $param string "transaction_type" Transaction type (BUY or SELL). + * $param int|null "quantity" Quantity to SELL. Not applicable on BUYs. + * $param float|null "amount" (Optional) Amount worth of units to purchase. Not applicable on SELLs + * $param string|null "tag" (Optional) An optional tag to apply to an order to identify it (alphanumeric, max 8 chars) + * @return string + * @throws DataException + * @throws GeneralException + * @throws InputException + * @throws NetworkException + * @throws OrderException + * @throws PermissionException + * @throws TokenException + */ + public function placeMFOrder(array $params): string + { + return $this->post("mf.order.place", $params); + } + + /** + * Cancel an mutual fund order. + * + * @param string $orderId Order id. + * @return string + * @throws DataException + * @throws GeneralException + * @throws InputException + * @throws NetworkException + * @throws OrderException + * @throws PermissionException + * @throws TokenException + */ + public function cancelMFOrder(string $orderId): string + { + return $this->delete("mf.order.cancel", ["order_id" => $orderId]); + } + + /** + * Get the list of mutual fund SIP's or individual SIP info. + * @param string|null $sip_id (Optional) SIP id. + * @return mixed + * @throws DataException + * @throws GeneralException + * @throws InputException + * @throws NetworkException + * @throws OrderException + * @throws PermissionException + * @throws TokenException + */ + public function getMFSIPS(?string $sip_id = null): mixed + { + if ($sip_id) { + return $this->formatResponse($this->get("mf.sip.info", ["sip_id" => $sip_id])); + } + + return $this->formatResponseArray($this->get("mf.sips")); + } + + /** + * Place an mutual fund order. + * + * @param array $params [Mutual fund SIP parameters](https://kite.trade/docs/connect/v3/mf/#sip-orders) + * $param string "tradingsymbol" Tradingsymbol (ISIN) of the fund. + * $param float "amount" Amount worth of units to purchase. Not applicable on SELLs + * $param int "instalments" Number of instalments to trigger. If set to -1, instalments are triggered at fixed intervals until the SIP is cancelled + * $param string "frequency" Order frequency. weekly, monthly, or quarterly. + * $param float|null "initial_amount" (Optional) Amount worth of units to purchase before the SIP starts. + * $param int|null "instalment_day" (Optional) If frequency is monthly, the day of the month (1, 5, 10, 15, 20, 25) to trigger the order on. + * $param string|null "tag" An optional (Optional) tag to apply to an order to identify it (alphanumeric, max 8 chars) + * @return string + * @throws DataException + * @throws GeneralException + * @throws InputException + * @throws NetworkException + * @throws OrderException + * @throws PermissionException + * @throws TokenException + */ + public function placeMFSIP(array $params): string + { + return $this->post("mf.sip.place", $params); + } + + /** + * Place an mutual fund order. + * + * @param string $sip_id Mutual fund SIP ID. + * @param array $params [Mutual fund SIP modify parameters](https://kite.trade/docs/connect/v1/#orders30) + * $param float "amount" Amount worth of units to purchase. Not applicable on SELLs + * $param int|null "instalments" (Optional) Number of instalments to trigger. If set to -1, instalments are triggered at fixed intervals until the SIP is cancelled + * $param string|null "frequency" (Optional) Order frequency. weekly, monthly, or quarterly. + * $param int|null "instalment_day" (Optional) If frequency is monthly, the day of the month (1, 5, 10, 15, 20, 25) to trigger the order on. + * $param string|null "status" (Optional) Pause or unpause an SIP (active or paused). + * @return string + * @throws DataException + * @throws GeneralException + * @throws InputException + * @throws NetworkException + * @throws OrderException + * @throws PermissionException + * @throws TokenException + */ + public function modifyMFSIP(string $sip_id, array $params): string + { + $params["sip_id"] = $sip_id; + + return $this->put("mf.sip.modify", $params); + } + + /** + * Cancel an mutual fund order. + * + * @param string $sip_id SIP id. + * @return string + * @throws DataException + * @throws GeneralException + * @throws InputException + * @throws NetworkException + * @throws OrderException + * @throws PermissionException + * @throws TokenException + */ + public function cancelMFSIP(string $sip_id): string + { + return $this->delete("mf.sip.cancel", ["sip_id" => $sip_id]); + } + + /** + * Get list of mutual fund instruments. + * + * @return array + * @throws DataException + * @throws GeneralException + * @throws InputException + * @throws NetworkException + * @throws OrderException + * @throws PermissionException + * @throws TokenException + */ + public function getMFInstruments(): array + { + return $this->parseMFInstrumentsToCSV($this->get("mf.instruments")); + } + + /** + * Get the list of all orders placed for the day. + * @return array + * @throws DataException + * @throws GeneralException + * @throws InputException + * @throws NetworkException + * @throws OrderException + * @throws PermissionException + * @throws TokenException + */ + public function getGTTs(): array + { + return $this->formatResponseArray($this->get("gtt.triggers")); + } + + /** + * Get detail of individual GTT order. + * @param string $triggerId Trigger ID + * @return mixed + * @throws DataException + * @throws GeneralException + * @throws InputException + * @throws NetworkException + * @throws OrderException + * @throws PermissionException + * @throws TokenException + */ + public function getGTT(string $triggerId): mixed + { + return $this->formatResponse($this->get("gtt.trigger_info", ["trigger_id" => $triggerId])); + } + + /** + * Delete an GTT order + * @param string $triggerId "trigger_id" Trigger ID + * @return mixed + * @throws DataException + * @throws GeneralException + * @throws InputException + * @throws NetworkException + * @throws OrderException + * @throws PermissionException + * @throws TokenException + */ + public function deleteGTT(string $triggerId) + { + return $this->delete("gtt.delete", ["trigger_id" => $triggerId]); + } + + /** + * @param mixed $params + * @return array + * @throws DataException + */ + private function getGTTPayload($params): array + { + if ($params["trigger_type"] == self::GTT_TYPE_OCO && count($params["trigger_values"]) != 2) { + throw new DataException("Invalid `trigger_values` for `OCO` order type"); + } + if ($params["trigger_type"] == self::GTT_TYPE_SINGLE && count($params["trigger_values"]) != 1) { + throw new DataException("Invalid `trigger_values` for `single` order type"); + } + $condition = [ + "exchange" => $params["exchange"], + "tradingsymbol" => $params["tradingsymbol"], + "trigger_values" => $params["trigger_values"], + "last_price" => (float)$params["last_price"], + ]; + $orders = []; + foreach ($params["orders"] as &$o) { + array_push($orders, [ + "transaction_type" => $o["transaction_type"], + "order_type" => $o["order_type"], + "product" => $o["product"], + "quantity" => (int)$o["quantity"], + "price" => (float)($o["price"]), + "exchange" => $params["exchange"], + "tradingsymbol" => $params["tradingsymbol"], + ]); + } + + return [ + "condition" => $condition, + "orders" => $orders, + ]; + } + + /** + * Place a GTT. Check [GTT documentation](https://kite.trade/docs/connect/v3/gtt/#placing-orders) for details. + *
+ * $params = [
+ * // GTT type, its either `$kite::GTT_TYPE_OCO` or `$kite::GTT_TYPE_SINGLE`.
+ * "trigger_type" => $kite::GTT_TYPE_OCO,
+ * // Tradingsymbol of the instrument (ex. RELIANCE, INFY).
+ * "tradingsymbol" => "SBIN",
+ * // Exchange in which instrument is listed (NSE, BSE, NFO, BFO, CDS, MCX).
+ * "exchange" => "NSE",
+ * // List of trigger values, number of items depends on trigger type.
+ * "trigger_values" => array(300, 400),
+ * // Price at which trigger is created. This is usually the last price of the instrument.
+ * "last_price" => 318,
+ * // List of orders. Check [order params](https://kite.trade/docs/connect/v3/orders/#regular-order-parameters) for all available params.
+ * "orders" => array([
+ * "transaction_type" => $kite::TRANSACTION_TYPE_SELL,
+ * "quantity" => 1,
+ * "product" => $kite::PRODUCT_CNC,
+ * "order_type" => $kite::ORDER_TYPE_LIMIT,
+ * "price" => 300
+ * ], [
+ * "transaction_type" => $kite::TRANSACTION_TYPE_SELL,
+ * "quantity" => 1,
+ * "product" => $kite::PRODUCT_CNC,
+ * "order_type" => $kite::ORDER_TYPE_LIMIT,
+ * "price" => 400
+ * ])
+ * ]
+ *
+ *
+ * @param array $params GTT Params. Check above for required fields.
+ * @return mixed
+ * @throws DataException
+ * @throws GeneralException
+ * @throws InputException
+ * @throws NetworkException
+ * @throws OrderException
+ * @throws PermissionException
+ * @throws TokenException
+ */
+ public function placeGTT(array $params)
+ {
+ $payload = $this->getGTTPayload($params);
+
+ return $this->post("gtt.place", [
+ "condition" => json_encode($payload["condition"]),
+ "orders" => json_encode($payload["orders"]),
+ "type" => $params["trigger_type"],
+ ]);
+ }
+
+ /**
+ * Modify GTT. Check [GTT documentation](https://kite.trade/docs/connect/v3/gtt/#modify-order) for details.
+ *
+ * $params = [
+ * // GTT type, its either `$kite::GTT_TYPE_OCO` or `$kite::GTT_TYPE_SINGLE`.
+ * "trigger_type" => $kite::GTT_TYPE_OCO,
+ * // Tradingsymbol of the instrument (ex. RELIANCE, INFY).
+ * "tradingsymbol" => "SBIN",
+ * // Exchange in which instrument is listed (NSE, BSE, NFO, BFO, CDS, MCX).
+ * "exchange" => "NSE",
+ * // List of trigger values, number of items depends on trigger type.
+ * "trigger_values" => array(300, 400),
+ * // Price at which trigger is created. This is usually the last price of the instrument.
+ * "last_price" => 318,
+ * // List of orders. Check [order params](https://kite.trade/docs/connect/v3/orders/#regular-order-parameters) for all available params.
+ * "orders" => array([
+ * "transaction_type" => $kite::TRANSACTION_TYPE_SELL,
+ * "quantity" => 1,
+ * "product" => $kite::PRODUCT_CNC,
+ * "order_type" => $kite::ORDER_TYPE_LIMIT,
+ * "price" => 300
+ * ], [
+ * "transaction_type" => $kite::TRANSACTION_TYPE_SELL,
+ * "quantity" => 1,
+ * "product" => $kite::PRODUCT_CNC,
+ * "order_type" => $kite::ORDER_TYPE_LIMIT,
+ * "price" => 400
+ * ])
+ * ]
+ *
+ * @param int $triggerId GTT Trigger ID
+ * @param array $params GTT Params. Check above for required fields.
+ * @return mixed
+ * @throws DataException
+ * @throws GeneralException
+ * @throws InputException
+ * @throws NetworkException
+ * @throws OrderException
+ * @throws PermissionException
+ * @throws TokenException
+ */
+ public function modifyGTT(int $triggerId, array $params)
+ {
+ $payload = $this->getGTTPayload($params);
+
+ return $this->put("gtt.modify", [
+ "condition" => json_encode($payload["condition"]),
+ "orders" => json_encode($payload["orders"]),
+ "type" => $params["trigger_type"],
+ "trigger_id" => $triggerId,
+ ]);
+ }
+
+ /**
+ * Format response array, For example datetime string to DateTime object
+ * @param mixed $data
+ * @return mixed
+ * @throws Exception
+ */
+ private function formatResponse($data)
+ {
+ foreach (self::$dateFields as $field) {
+ if (isset($data->$field) && strlen($data->$field) == 19) {
+ $data->$field = new DateTime($data->$field, new DateTimeZone("Asia/Kolkata"));
+ }
+ }
+
+ return $data;
+ }
+
+ /**
+ * Format array of responses
+ * @param mixed $data
+ * @return array
+ * @throws Exception
+ */
+ private function formatResponseArray($data): array
+ {
+ $results = [];
+ foreach ($data as $k => $item) {
+ $results[$k] = $this->formatResponse($item);
+ }
+
+ return $results;
+ }
+
+ /**
+ * Alias for sending a GET request.
+ *
+ * @param string $route Route name mapped in self::$routes.
+ * @param array|null $params Request parameters.
+ * @param string $headerContent
+ * @return mixed Array or object (deserialised JSON).
+ * @throws DataException
+ * @throws GeneralException
+ * @throws InputException
+ * @throws NetworkException
+ * @throws OrderException
+ * @throws PermissionException
+ * @throws TokenException
+ */
+ private function get(string $route, array $params = [], string $headerContent = '')
+ {
+ return $this->request($route, "GET", $params, $headerContent);
+ }
+
+ /**
+ * Alias for sending a GET request.
+ *
+ * @param string $route Route name mapped in self::$routes.
+ * @param array|null $params Request parameters.
+ * @param string $headerContent
+ * @return mixed Array or object (deserialised JSON).
+ * @throws DataException
+ * @throws GeneralException
+ * @throws InputException
+ * @throws NetworkException
+ * @throws OrderException
+ * @throws PermissionException
+ * @throws TokenException
+ */
+ private function post(string $route, array $params = [], string $headerContent = '')
+ {
+ return $this->request($route, "POST", $params, $headerContent);
+ }
+
+ /**
+ * Alias for sending a PUT request.
+ *
+ * @param string $route Route name mapped in self::$routes.
+ * @param array|null $params Request parameters.
+ * @param string $headerContent
+ * @return mixed Array or object (deserialised JSON).
+ * @throws DataException
+ * @throws GeneralException
+ * @throws InputException
+ * @throws NetworkException
+ * @throws OrderException
+ * @throws PermissionException
+ * @throws TokenException
+ */
+ private function put(string $route, array $params = [], string $headerContent = '')
+ {
+ return $this->request($route, "PUT", $params, $headerContent);
+ }
+
+ /**
+ * Alias for sending a GET request.
+ *
+ * @param string $route Route name mapped in self::$routes.
+ * @param array|null $params Request parameters.
+ * @param string $headerContent
+ * @return mixed Array or object (deserialised JSON).
+ * @throws DataException
+ * @throws GeneralException
+ * @throws InputException
+ * @throws NetworkException
+ * @throws OrderException
+ * @throws PermissionException
+ * @throws TokenException
+ */
+ private function delete(string $route, array $params = [], string $headerContent = '')
+ {
+ return $this->request($route, "DELETE", $params, $headerContent);
+ }
+
+ /**
+ * Make an HTTP request.
+ *
+ * @param string $route Route name mapped in self::$routes.
+ * @param string $method The HTTP method to send (GET, POST, PUT, DELETE).
+ * @param array|null $params Request parameters.
+ * @param string $headerContent Header content
+ * @return mixed Array or object (deserialised JSON).
+ * @throws DataException
+ * @throws GeneralException
+ * @throws InputException
+ * @throws NetworkException
+ * @throws OrderException
+ * @throws PermissionException
+ * @throws TokenException
+ */
+ private function request(string $route, string $method, array $params, string $headerContent)
+ {
+ $uri = $this->routes[$route];
+ // 'RESTful' URLs.
+ if (strpos($uri, "{") !== false) {
+ foreach ($params as $key => $value) {
+ $uri = str_replace("{" . $key . "}", (string)$value, $uri);
+ }
+ }
+
+ $url = $this->baseUrl . $uri;
+
+ if ($this->debug) {
+ print("Request: " . $method . " " . $url . "\n");
+ var_dump($params);
+ }
+ // Set the header content type
+ if ($headerContent) {
+ $content_type = $headerContent;
+ } else {
+ // By default set header content type to be form-urlencoded
+ $content_type = "application/x-www-form-urlencoded";
+ }
+
+ // Prepare the request header
+ $request_headers = [
+ "Content-Type" => $content_type,
+ "User-Agent" => "phpkiteconnect/" . self::VERSION,
+ "X-Kite-Version" => 3,
+ ];
+
+ if ($this->apiKey && $this->accessToken) {
+ $request_headers["Authorization"] = "token " . $this->apiKey . ":" . $this->accessToken;
+ }
+ // Make the HTTP request.
+ $resp = $this->guzzle($url, $method, $request_headers, $params, $this->guzzleClient);
+
+ $headers = $resp["headers"];
+ $result = $resp["body"];
+
+ if ($this->debug) {
+ print("Response :" . $result . "\n");
+ }
+ if (empty($headers["Content-Type"])) {
+ throw new DataException("Unknown content-type in response");
+ } elseif (strpos($headers["Content-Type"][0], "application/json") !== false) {
+ $json = json_decode($result);
+ if (! $json) {
+ throw new DataException("Couldn't parse JSON response");
+ }
+
+ // Token error.
+ if ($json->status == "error") {
+ if ($headers["status_code"] == 403) {
+ if ($this->sessionHook) {
+ $this->sessionHook->call($this);
+
+ return null;
+ }
+ }
+ $this->throwSuitableException($headers, $json);
+ }
+ return $json->data;
+ } elseif (strpos($headers["Content-Type"][0], "text/csv") !== false) {
+ return $result;
+ } else {
+ throw new DataException("Invalid response: " . $result, $headers["status_code"]);
+ }
+ }
+
+ /**
+ * Make an HTTP request using the PHP Guzzle http client.
+ *
+ * @param string $url The full URL to retrieve
+ * @param string $method The HTTP method to send (GET, POST, PUT, DELETE).
+ * @param array|null $headers Array of HTTP request headers to send.
+ * @param array|null $params Array of key=>value request parameters.
+ * @return array Returns an array with response "headers" and "body".
+ */
+ private function guzzle(string $url, string $method, ?array $headers, $params = null, $guzzleClient = null): array
+ {
+ // set header to Guzzle http client
+ // mock patching isn't allowed in PHP
+ // Need to pass guzzle client as dependency to mock http response for unit tests
+ if ($guzzleClient) {
+ $client = $guzzleClient;
+ } else {
+ $client = new Client(['headers' => $headers, 'timeout' => $this->timeout]);
+ }
+
+ // declare http body array
+ $body_array = [];
+ if ($method == "POST" || $method == "PUT") {
+ // send JSON body payload for JSON content-type requested
+ if($headers['Content-Type'] == 'application/json') {
+ $body_array = ['body' => implode(" ",$params)];
+ } else {
+ $body_array = ['form_params' => $params];
+ }
+ } elseif ($method == "GET" || $method == "DELETE") {
+ $payload = http_build_query($params && is_array($params) ? $params : []);
+ // remove un-required url encoded strings
+ $payload = preg_replace("/%5B(\d+?)%5D/", "", $payload);
+ $body_array = ['query' => $payload];
+ }
+ try {
+ $response = $client->request($method, $url, $body_array);
+ } catch(RequestException $e){
+ // fetch all error response field
+ $response = $e->getResponse();
+ }
+
+ $result = $response->getBody()->getContents();
+
+ $response_headers = $response->getHeaders();
+ // add Status Code in response header
+ $response_headers['status_code'] = $response->getStatusCode();
+ return ["headers" => $response_headers, "body" => $result];
+ }
+
+ /**
+ * Parse a CSV dump into an array of objects.
+ *
+ * @param string $csv Complete CSV dump.
+ * @return array
+ * @throws Exception
+ */
+ private function parseInstrumentsToCSV(string $csv): array
+ {
+ $lines = explode("\n", $csv);
+
+ $records = [];
+ $head = [];
+ for ($count = 0; $count < count($lines); $count++) {
+ $colums = str_getcsv($lines[$count]);
+ if ($colums) {
+ if (count($colums) < 5) {
+ //why this condition is necessary ?
+ continue;
+ }
+
+ // First line is the header.
+ if ($count === 0) {
+ $head = $colums;
+
+ continue;
+ }
+
+ // Combine header columns + values to an associative array
+ // and then to an object;
+ $record = (object)array_combine($head, $colums);
+ $record->last_price = floatval($record->last_price);
+ $record->strike = floatval($record->strike);
+ $record->tick_size = floatval($record->tick_size);
+ $record->lot_size = floatval($record->lot_size);
+
+ if (! empty($record->expiry) && strlen($record->expiry) == 10) {
+ $record->expiry = new DateTime($record->expiry, new DateTimeZone("Asia/Kolkata"));
+ }
+
+ $records[] = $record;
+ }
+ }
+
+ return $records;
+ }
+
+ /**
+ * Parse a CSV dump into an array of objects.
+ *
+ * @param string $csv Complete CSV dump.
+ * @return array
+ * @throws Exception
+ */
+ private function parseMFInstrumentsToCSV(string $csv): array
+ {
+ $lines = explode("\n", $csv);
+
+ $records = [];
+ $head = [];
+ for ($n = 0; $n < count($lines); $n++) {
+ if ($cols = @str_getcsv($lines[$n])) {
+ if (count($cols) < 5) {
+ continue;
+ }
+
+ // First line is the header.
+ if ($n === 0) {
+ $head = $cols;
+
+ continue;
+ }
+
+ // Combine header columns + values to an associative array
+ // and then to an object;
+ $o = (object)array_combine($head, $cols);
+ $o->minimum_purchase_amount = floatval($o->minimum_purchase_amount);
+ $o->purchase_amount_multiplier = floatval($o->purchase_amount_multiplier);
+ $o->minimum_additional_purchase_amount = floatval($o->minimum_additional_purchase_amount);
+ $o->minimum_redemption_quantity = floatval($o->minimum_redemption_quantity);
+ $o->redemption_quantity_multiplier = floatval($o->redemption_quantity_multiplier);
+ $o->last_price = floatval($o->last_price);
+ $o->purchase_allowed = boolval(intval($o->purchase_allowed));
+ $o->redemption_allowed = boolval(intval($o->redemption_allowed));
+
+ if (! empty($o->last_price_date) && strlen($o->last_price_date) == 10) {
+ $o->last_price_date = new DateTime($o->last_price_date, new DateTimeZone("Asia/Kolkata"));
+ }
+
+ $records[] = $o;
+ }
+ }
+
+ return $records;
+ }
+
+ /**
+ * Throw Exception based on response
+ *
+ * @param array $headers
+ * @param mixed $json
+ * @return void
+ * @throws DataException
+ * @throws GeneralException
+ * @throws OrderException
+ * @throws PermissionException
+ * @throws NetworkException
+ * @throws InputException
+ * @throws TokenException
+ */
+ private function throwSuitableException(array $headers, $json): void
+ {
+ switch ($json->error_type) {
+ case 'DataException':
+ throw new DataException($json->message, $headers['status_code']);
+ case 'InputException':
+ throw new InputException($json->message, $headers['status_code']);
+ case 'NetworkException':
+ throw new NetworkException($json->message, $headers['status_code']);
+ case 'OrderException':
+ throw new OrderException($json->message, $headers['status_code']);
+ case 'PermissionException':
+ throw new PermissionException($json->message, $headers['status_code']);
+ case 'TokenException':
+ throw new TokenException($json->message, $headers['status_code']);
+ default:
+ throw new GeneralException($json->message, $headers['status_code']);
+ }
+ }
+}
+?>
\ No newline at end of file
diff --git a/tests/KiteConnectTest.php b/tests/KiteConnectTest.php
new file mode 100644
index 0000000..0661a70
--- /dev/null
+++ b/tests/KiteConnectTest.php
@@ -0,0 +1,524 @@
+getLoginURL();
+ $expectedLoginUrl = 'https://kite.trade/connect/login?api_key=token&v=3';
+ $this->assertEquals($expectedLoginUrl, $actualLoginUrl);
+ }
+
+ /**
+ * @test
+ * @return void
+ */
+ public function test_login_url_is_string(): void
+ {
+ $kiteConnect = new KiteConnect('token');
+ $loginUrl = $kiteConnect->getLoginURL();
+ $this->assertIsString($loginUrl);
+ }
+
+ /**
+ * @test
+ * @return void
+ */
+ public function it_can_be_instantiated_with_token(): void
+ {
+ $kiteConnect = new KiteConnect('token');
+ $this->assertInstanceOf(KiteConnect::class, $kiteConnect);
+ }
+
+ /**
+ * @test
+ * @return void
+ */
+ public function it_can_be_instantiated_with_token_and_access_token(): void
+ {
+ $kiteConnect = new KiteConnect('token', 'access_token');
+ $this->assertInstanceOf(KiteConnect::class, $kiteConnect);
+ }
+
+ /**
+ * @test Mock intialization
+ */
+ public function initializeMock()
+ {
+ $timeout = 7;
+ $mock_data = new MockJson();
+ // Create a mock and queue required responses.
+ $client = new Client(['handler' => $mock_data->generateMock()]);
+ // Inject guzzleClient
+ $kiteConnect = new KiteConnect('api_key', 'access_token', NULL, false, $timeout, $client);
+ $this->assertNotNull($kiteConnect);
+
+ return $kiteConnect;
+ }
+
+ /**
+ * @depends initializeMock
+ * @test getProfile
+ */
+ public function getProfileTest($kiteConnect): void
+ {
+ $response = $kiteConnect->getProfile();
+
+ $this->assertObjectHasAttribute('user_id',$response);
+ $this->assertObjectHasAttribute('user_name',$response);
+ $this->assertObjectHasAttribute('exchanges',$response);
+ $this->assertObjectHasAttribute('meta',$response);
+ }
+
+ /**
+ * @depends initializeMock
+ * @test getMargins
+ */
+ public function getMarginsTest($kiteConnect): void
+ {
+ $response = $kiteConnect->getMargins();
+
+ $this->assertObjectHasAttribute('equity',$response);
+ $this->assertObjectHasAttribute('commodity',$response);
+ }
+
+ /**
+ * @depends initializeMock
+ * @test getQuote
+ */
+ public function getQuoteTest($kiteConnect): void
+ {
+ $response = $kiteConnect->getQuote(['NSE:INFY', 'NSE:SBIN']);
+
+ $this->assertArrayHasKey('NSE:INFY', $response);
+ $this->assertArrayHasKey('NSE:SBIN', $response);
+
+ foreach ($response as $values) {
+ $this->assertObjectHasAttribute('instrument_token',$values);
+ $this->assertObjectHasAttribute('ohlc',$values);
+ $this->assertObjectHasAttribute('depth',$values);
+ }
+ }
+
+ /**
+ * @depends initializeMock
+ * @test getOHLC
+ */
+ public function getOHLCTest($kiteConnect): void
+ {
+ $response = $kiteConnect->getOHLC(['NSE:INFY', 'NSE:SBIN']);
+
+ $this->assertObjectHasAttribute('NSE:INFY', $response);
+ $this->assertObjectHasAttribute('NSE:SBIN', $response);
+
+ foreach ($response as $values) {
+ $this->assertObjectHasAttribute('instrument_token',$values);
+ $this->assertObjectHasAttribute('ohlc',$values);
+ $this->assertObjectHasAttribute('last_price',$values);
+ }
+ }
+
+ /**
+ * @depends initializeMock
+ * @test getLTP
+ */
+ public function getLTPTest($kiteConnect): void
+ {
+ $response = $kiteConnect->getLTP(['NSE:INFY', 'NSE:SBIN']);
+
+ $this->assertObjectHasAttribute('NSE:INFY', $response);
+ $this->assertObjectHasAttribute('NSE:SBIN', $response);
+
+ foreach ($response as $values) {
+ $this->assertObjectHasAttribute('instrument_token',$values);
+ $this->assertObjectHasAttribute('last_price',$values);
+ }
+ }
+
+ /**
+ * @depends initializeMock
+ * @test getHoldings
+ */
+ public function getHoldingsTest($kiteConnect): void
+ {
+ $response = $kiteConnect->getHoldings();
+
+ foreach ($response as $values) {
+ $this->assertObjectHasAttribute('tradingsymbol',$values);
+ $this->assertObjectHasAttribute('exchange',$values);
+ $this->assertObjectHasAttribute('pnl',$values);
+ }
+ }
+
+ /**
+ * @depends initializeMock
+ * @test getPositions
+ */
+ public function getPositionsTest($kiteConnect): void
+ {
+ $response = $kiteConnect->getPositions();
+ $this->assertObjectHasAttribute('net',$response);
+
+ foreach ($response as $values) {
+ foreach ($values as $value2){
+ $this->assertObjectHasAttribute('tradingsymbol',$value2);
+ $this->assertObjectHasAttribute('exchange',$value2);
+ $this->assertObjectHasAttribute('average_price',$value2);
+ }
+ }
+
+ }
+
+ /**
+ * @depends initializeMock
+ * @test placeOrder
+ */
+ public function placeOrderTest($kiteConnect): void
+ {
+ $response = $kiteConnect->placeOrder("regular", [
+ "tradingsymbol" => "INFY",
+ "exchange" => "NSE",
+ "quantity" => 1,
+ "transaction_type" => "BUY",
+ "order_type" => "MARKET",
+ "product" => "NRML"
+ ]);
+
+ $this->assertObjectHasAttribute('order_id',$response);
+
+ }
+
+ /**
+ * @depends initializeMock
+ * @test getOrders
+ */
+ public function getOrdersTest($kiteConnect): void
+ {
+ $response = $kiteConnect->getOrders();
+
+ foreach ($response as $values) {
+ $this->assertObjectHasAttribute('order_id',$values);
+ $this->assertObjectHasAttribute('exchange_timestamp',$values);
+ $this->assertObjectHasAttribute('status',$values);
+ $this->assertObjectHasAttribute('order_id',$values);
+ }
+
+ }
+
+ /**
+ * @depends initializeMock
+ * @test getOrderHistory
+ */
+ public function getOrderHistoryTest($kiteConnect): void
+ {
+ $response = $kiteConnect->getOrderHistory('123456789');
+
+ foreach ($response as $values) {
+ $this->assertObjectHasAttribute('order_id',$values);
+ $this->assertObjectHasAttribute('exchange_timestamp',$values);
+ $this->assertObjectHasAttribute('status',$values);
+ }
+
+ }
+
+ /**
+ * @depends initializeMock
+ * @test getOrderTrades
+ */
+ public function getOrderTradesTest($kiteConnect): void
+ {
+ $response = $kiteConnect->getOrderTrades('123456789');
+
+ foreach ($response as $values) {
+ $this->assertObjectHasAttribute('average_price',$values);
+ $this->assertObjectHasAttribute('transaction_type',$values);
+ $this->assertObjectHasAttribute('order_timestamp',$values);
+ $this->assertObjectHasAttribute('order_id',$values);
+ }
+
+ }
+
+ /**
+ * @depends initializeMock
+ * @test getTrades
+ */
+ public function getTradesTest($kiteConnect): void
+ {
+ $response = $kiteConnect->getTrades();
+
+ foreach ($response as $values) {
+ $this->assertObjectHasAttribute('trade_id',$values);
+ $this->assertObjectHasAttribute('exchange_order_id',$values);
+ $this->assertObjectHasAttribute('order_id',$values);
+ $this->assertObjectHasAttribute('instrument_token',$values);
+ }
+
+ }
+
+ /**
+ * @depends initializeMock
+ * @test placeGTT
+ */
+ public function placeGTTTest($kiteConnect): void
+ {
+ $response = $kiteConnect->placeGTT([
+ "trigger_type" => $kiteConnect::GTT_TYPE_SINGLE,
+ "tradingsymbol" => "TATAMOTORS",
+ "exchange" => "NSE",
+ "trigger_values" => array(310),
+ "last_price" => 315,
+ "orders" => array([
+ "transaction_type" => $kiteConnect::TRANSACTION_TYPE_SELL,
+ "quantity" => 1,
+ "product" => $kiteConnect::PRODUCT_CNC,
+ "order_type" => $kiteConnect::ORDER_TYPE_LIMIT,
+ "price" => 300],
+ [
+ "transaction_type" => $kiteConnect::TRANSACTION_TYPE_SELL,
+ "quantity" => 1,
+ "product" => $kiteConnect::PRODUCT_CNC,
+ "order_type" => $kiteConnect::ORDER_TYPE_LIMIT,
+ "price" => 400
+ ])]);
+
+ $this->assertObjectHasAttribute('trigger_id',$response);
+ }
+
+ /**
+ * @depends initializeMock
+ * @test getGTTs
+ */
+ public function getGTTsTest($kiteConnect): void
+ {
+ $response = $kiteConnect->getGTTs();
+
+ foreach ($response as $values) {
+ $this->assertObjectHasAttribute('id',$values);
+ $this->assertObjectHasAttribute('created_at',$values);
+ $this->assertObjectHasAttribute('status',$values);
+ $this->assertObjectHasAttribute('condition',$values);
+ }
+
+ }
+
+ /**
+ * @depends initializeMock
+ * @test getGTT
+ */
+ public function getGTTTest($kiteConnect): void
+ {
+ $response = $kiteConnect->getGTT('123');
+
+ $this->assertObjectHasAttribute('id',$response);
+ $this->assertObjectHasAttribute('user_id',$response);
+ $this->assertObjectHasAttribute('orders',$response);
+ $this->assertObjectHasAttribute('condition',$response);
+
+ }
+
+ /**
+ * @depends initializeMock
+ * @test modifyGTT
+ */
+ public function modifyGTTTest($kiteConnect): void
+ {
+ $response = $kiteConnect->modifyGTT(123, [
+ "orders" => array([
+ "transaction_type" => $kiteConnect::TRANSACTION_TYPE_SELL,
+ "quantity" => 1,
+ "product" => $kiteConnect::PRODUCT_CNC,
+ "order_type" => $kiteConnect::ORDER_TYPE_LIMIT,
+ "price" => 300],
+ [
+ "transaction_type" => $kiteConnect::TRANSACTION_TYPE_SELL,
+ "quantity" => 1,
+ "product" => $kiteConnect::PRODUCT_CNC,
+ "order_type" => $kiteConnect::ORDER_TYPE_LIMIT,
+ "price" => 400
+ ]),
+ "tradingsymbol" => "TATAMOTORS",
+ "exchange" => "NSE",
+ "trigger_values" => array(310),
+ "last_price" => 315,
+ "trigger_type" => $kiteConnect::GTT_TYPE_SINGLE,
+ "trigger_id" => 123]);
+
+ $this->assertObjectHasAttribute('trigger_id',$response);
+ }
+
+ /**
+ * @depends initializeMock
+ * @test deleteGTT
+ */
+ public function deleteGTTTest($kiteConnect): void
+ {
+ $response = $kiteConnect->deleteGTT('123');
+
+ $this->assertObjectHasAttribute('trigger_id',$response);
+
+ }
+
+ /**
+ * @depends initializeMock
+ * @test getHistoricalData
+ */
+ public function getHistoricalDataTest($kiteConnect): void
+ {
+ $response = $kiteConnect->getHistoricalData(15495682, 'minute', '2021-01-20', '2021-01-25');
+
+ foreach ($response as $values) {
+ $this->assertObjectHasAttribute('date',$values);
+ $this->assertObjectHasAttribute('open',$values);
+ $this->assertObjectHasAttribute('high',$values);
+ $this->assertObjectHasAttribute('low',$values);
+ $this->assertObjectHasAttribute('close',$values);
+ $this->assertObjectHasAttribute('volume',$values);
+ }
+
+ }
+
+ /**
+ * @depends initializeMock
+ * @test getMFOrders
+ */
+ public function getMFOrdersTest($kiteConnect): void
+ {
+ $response = $kiteConnect->getMFOrders();
+
+ foreach ($response as $values) {
+ $this->assertObjectHasAttribute('order_id',$values);
+ $this->assertObjectHasAttribute('tradingsymbol',$values);
+ $this->assertObjectHasAttribute('purchase_type',$values);
+ $this->assertObjectHasAttribute('fund',$values);
+ }
+
+ }
+
+ /**
+ * @depends initializeMock
+ * @test getMFOrders
+ */
+ public function getMFOrderindTest($kiteConnect): void
+ {
+ $response = $kiteConnect->getMFOrders('123456789');
+
+ $this->assertObjectHasAttribute('order_id',$response);
+ $this->assertObjectHasAttribute('fund',$response);
+ $this->assertObjectHasAttribute('order_timestamp',$response);
+ $this->assertObjectHasAttribute('amount',$response);
+ }
+
+ /**
+ * @depends initializeMock
+ * @test getMFSIPS
+ */
+ public function getMFSIPSTest($kiteConnect): void
+ {
+ $response = $kiteConnect->getMFSIPS();
+
+ foreach ($response as $values) {
+ $this->assertObjectHasAttribute('sip_id',$values);
+ $this->assertObjectHasAttribute('fund',$values);
+ $this->assertObjectHasAttribute('instalment_amount',$values);
+ $this->assertObjectHasAttribute('dividend_type',$values);
+ }
+ }
+
+ /**
+ * @depends initializeMock
+ * @test getMFSIPS
+ */
+ public function getMFSIPSindvTest($kiteConnect): void
+ {
+ $response = $kiteConnect->getMFSIPS('123456789');
+
+ $this->assertObjectHasAttribute('sip_id',$response);
+ $this->assertObjectHasAttribute('last_instalment',$response);
+ $this->assertObjectHasAttribute('pending_instalments',$response);
+ $this->assertObjectHasAttribute('instalment_date',$response);
+ }
+
+ /**
+ * @depends initializeMock
+ * @test getMFHoldings
+ */
+ public function getMFHoldingsTest($kiteConnect): void
+ {
+ $response = $kiteConnect->getMFHoldings();
+
+ foreach ($response as $values) {
+ $this->assertObjectHasAttribute('folio',$values);
+ $this->assertObjectHasAttribute('fund',$values);
+ $this->assertObjectHasAttribute('tradingsymbol',$values);
+ $this->assertObjectHasAttribute('pnl',$values);
+ }
+ }
+
+ /**
+ * @depends initializeMock
+ * @test getInstruments
+ */
+ public function getInstrumentsTest($kiteConnect): void
+ {
+ $response = $kiteConnect->getInstruments();
+
+ foreach ($response as $values) {
+ $this->assertObjectHasAttribute('instrument_token',$values);
+ $this->assertObjectHasAttribute('exchange_token',$values);
+ $this->assertObjectHasAttribute('tradingsymbol',$values);
+ $this->assertObjectHasAttribute('name',$values);
+ }
+ }
+
+ /**
+ * @depends initializeMock
+ * @test getInstruments with Exchange
+ */
+ public function getInstrumentsExchangeTest($kiteConnect): void
+ {
+ $response = $kiteConnect->getInstruments('NSE');
+
+ foreach ($response as $values) {
+ $this->assertObjectHasAttribute('instrument_token',$values);
+ $this->assertObjectHasAttribute('exchange_token',$values);
+ $this->assertObjectHasAttribute('tradingsymbol',$values);
+ $this->assertObjectHasAttribute('name',$values);
+ }
+ }
+
+ /**
+ * @depends initializeMock
+ * @test getMFInstruments
+ */
+ public function getMFInstrumentsTest($kiteConnect): void
+ {
+ $response = $kiteConnect->getMFInstruments();
+
+ foreach ($response as $values) {
+ $this->assertObjectHasAttribute('tradingsymbol',$values);
+ $this->assertObjectHasAttribute('amc',$values);
+ $this->assertObjectHasAttribute('scheme_type',$values);
+ $this->assertObjectHasAttribute('redemption_allowed',$values);
+ }
+ }
+
+}
diff --git a/tests/MockJson.php b/tests/MockJson.php
new file mode 100644
index 0000000..4b228b5
--- /dev/null
+++ b/tests/MockJson.php
@@ -0,0 +1,64 @@
+ 'application/json'];
+ $mock_files = [
+ "profile.json",
+ "margins.json",
+ "quote.json",
+ "ohlc.json",
+ "ltp.json",
+ "holdings.json",
+ "positions.json",
+ "order_response.json",
+ "orders.json",
+ "order_info.json",
+ "order_trades.json",
+ "trades.json",
+ "gtt_place_order.json",
+ "gtt_get_orders.json",
+ "gtt_get_order.json",
+ "gtt_modify_order.json",
+ "gtt_delete_order.json",
+ "historical_minute.json",
+ "mf_orders.json",
+ "mf_orders_info.json",
+ "mf_sips.json",
+ "mf_sip_info.json",
+ "mf_holdings.json"
+ ];
+ $response_array = array();
+ foreach ($mock_files as $values) {
+ $response_array[] = new Response($status_code, $header_content, $this->fetchMock($values));
+ }
+ // add all text/csv header based content-type response
+ $response_array[] = new Response($status_code, ['Content-Type' => 'text/csv'], $this->fetchMock("instruments_all.csv"));
+ $response_array[] = new Response($status_code, ['Content-Type' => 'text/csv'], $this->fetchMock("instruments_nse.csv"));
+ $response_array[] = new Response($status_code, ['Content-Type' => 'text/csv'], $this->fetchMock("mf_instruments.csv"));
+
+ $mock = new MockHandler($response_array);
+ $handlerStack = HandlerStack::create($mock);
+
+ return $handlerStack;
+ }
+
+ public function fetchMock(string $route)
+ {
+ // root mock response file location
+ $file_root = "./tests/mock_responses/";
+ $fetch_mock = file_get_contents($file_root. $route);
+ return $fetch_mock;
+ }
+}
+
+?>
\ No newline at end of file
diff --git a/tests/mock_responses/gtt_delete_order.json b/tests/mock_responses/gtt_delete_order.json
new file mode 100644
index 0000000..b6fccbd
--- /dev/null
+++ b/tests/mock_responses/gtt_delete_order.json
@@ -0,0 +1 @@
+{"status":"success","data":{"trigger_id":123}}
\ No newline at end of file
diff --git a/tests/mock_responses/gtt_get_order.json b/tests/mock_responses/gtt_get_order.json
new file mode 100644
index 0000000..7cf4864
--- /dev/null
+++ b/tests/mock_responses/gtt_get_order.json
@@ -0,0 +1,72 @@
+{
+ "status": "success",
+ "data": {
+ "id": 123,
+ "user_id": "PH2965",
+ "parent_trigger": null,
+ "type": "two-leg",
+ "created_at": "2019-09-09 17:13:26",
+ "updated_at": "2019-09-09 17:13:26",
+ "expires_at": "2020-09-09 17:13:26",
+ "status": "active",
+ "condition": {
+ "exchange": "NSE",
+ "last_price": 278,
+ "tradingsymbol": "SBIN",
+ "trigger_values": [
+ 264.1,
+ 291.9
+ ],
+ "instrument_token": 779521
+ },
+ "orders": [
+ {
+ "account_id": "",
+ "parent_order_id": "",
+ "exchange": "NSE",
+ "tradingsymbol": "SBIN",
+ "validity": "",
+ "product": "CNC",
+ "order_type": "LIMIT",
+ "transaction_type": "SELL",
+ "quantity": 1,
+ "disclosed_quantity": 0,
+ "price": 264.1,
+ "trigger_price": 0,
+ "ltp_atp": "",
+ "squareoff_abs_tick": "",
+ "stoploss_abs_tick": "",
+ "squareoff": 0,
+ "stoploss": 0,
+ "trailing_stoploss": 0,
+ "meta": "",
+ "guid": "",
+ "result": null
+ },
+ {
+ "account_id": "",
+ "parent_order_id": "",
+ "exchange": "NSE",
+ "tradingsymbol": "SBIN",
+ "validity": "",
+ "product": "CNC",
+ "order_type": "LIMIT",
+ "transaction_type": "SELL",
+ "quantity": 1,
+ "disclosed_quantity": 0,
+ "price": 291.9,
+ "trigger_price": 0,
+ "ltp_atp": "",
+ "squareoff_abs_tick": "",
+ "stoploss_abs_tick": "",
+ "squareoff": 0,
+ "stoploss": 0,
+ "trailing_stoploss": 0,
+ "meta": "",
+ "guid": "",
+ "result": null
+ }
+ ],
+ "meta": {}
+ }
+}
\ No newline at end of file
diff --git a/tests/mock_responses/gtt_get_orders.json b/tests/mock_responses/gtt_get_orders.json
new file mode 100644
index 0000000..765e5f3
--- /dev/null
+++ b/tests/mock_responses/gtt_get_orders.json
@@ -0,0 +1,267 @@
+{
+ "status": "success",
+ "data": [
+ {
+ "id": 105402,
+ "user_id": "PH2965",
+ "parent_trigger": null,
+ "type": "two-leg",
+ "created_at": "2019-09-09 17:13:26",
+ "updated_at": "2019-09-09 17:13:26",
+ "expires_at": "2020-09-09 17:13:26",
+ "status": "active",
+ "condition": {
+ "exchange": "NSE",
+ "last_price": 278,
+ "tradingsymbol": "SBIN",
+ "trigger_values": [
+ 264.1,
+ 291.9
+ ],
+ "instrument_token": 779521
+ },
+ "orders": [
+ {
+ "account_id": "",
+ "parent_order_id": "",
+ "exchange": "NSE",
+ "tradingsymbol": "SBIN",
+ "validity": "",
+ "product": "CNC",
+ "order_type": "LIMIT",
+ "transaction_type": "SELL",
+ "quantity": 1,
+ "disclosed_quantity": 0,
+ "price": 264.1,
+ "trigger_price": 0,
+ "ltp_atp": "",
+ "squareoff_abs_tick": "",
+ "stoploss_abs_tick": "",
+ "squareoff": 0,
+ "stoploss": 0,
+ "trailing_stoploss": 0,
+ "meta": "",
+ "guid": "",
+ "result": null
+ },
+ {
+ "account_id": "",
+ "parent_order_id": "",
+ "exchange": "NSE",
+ "tradingsymbol": "SBIN",
+ "validity": "",
+ "product": "CNC",
+ "order_type": "LIMIT",
+ "transaction_type": "SELL",
+ "quantity": 1,
+ "disclosed_quantity": 0,
+ "price": 291.9,
+ "trigger_price": 0,
+ "ltp_atp": "",
+ "squareoff_abs_tick": "",
+ "stoploss_abs_tick": "",
+ "squareoff": 0,
+ "stoploss": 0,
+ "trailing_stoploss": 0,
+ "meta": "",
+ "guid": "",
+ "result": null
+ }
+ ],
+ "meta": {}
+ },
+ {
+ "id": 105099,
+ "user_id": "PH2965",
+ "parent_trigger": null,
+ "type": "two-leg",
+ "created_at": "2019-09-09 15:13:22",
+ "updated_at": "2019-09-09 15:15:08",
+ "expires_at": "2020-01-01 12:00:00",
+ "status": "triggered",
+ "condition": {
+ "exchange": "NSE",
+ "last_price": 102.6,
+ "tradingsymbol": "RAIN",
+ "trigger_values": [
+ 102,
+ 103.7
+ ],
+ "instrument_token": 3926273
+ },
+ "orders": [
+ {
+ "account_id": "",
+ "parent_order_id": "",
+ "exchange": "NSE",
+ "tradingsymbol": "RAIN",
+ "validity": "",
+ "product": "CNC",
+ "order_type": "LIMIT",
+ "transaction_type": "SELL",
+ "quantity": 1,
+ "disclosed_quantity": 0,
+ "price": 1,
+ "trigger_price": 0,
+ "ltp_atp": "",
+ "squareoff_abs_tick": "",
+ "stoploss_abs_tick": "",
+ "squareoff": 0,
+ "stoploss": 0,
+ "trailing_stoploss": 0,
+ "meta": "",
+ "guid": "",
+ "result": null
+ },
+ {
+ "account_id": "",
+ "parent_order_id": "",
+ "exchange": "NSE",
+ "tradingsymbol": "RAIN",
+ "validity": "",
+ "product": "CNC",
+ "order_type": "LIMIT",
+ "transaction_type": "SELL",
+ "quantity": 1,
+ "disclosed_quantity": 0,
+ "price": 1,
+ "trigger_price": 0,
+ "ltp_atp": "",
+ "squareoff_abs_tick": "",
+ "stoploss_abs_tick": "",
+ "squareoff": 0,
+ "stoploss": 0,
+ "trailing_stoploss": 0,
+ "meta": "",
+ "guid": "",
+ "result": {
+ "account_id": "PH2965",
+ "parent_order_id": "",
+ "exchange": "NSE",
+ "tradingsymbol": "RAIN",
+ "validity": "DAY",
+ "product": "CNC",
+ "order_type": "LIMIT",
+ "transaction_type": "SELL",
+ "quantity": 1,
+ "disclosed_quantity": 0,
+ "price": 1,
+ "trigger_price": 0,
+ "ltp_atp": "LTP",
+ "squareoff_abs_tick": "absolute",
+ "stoploss_abs_tick": "absolute",
+ "squareoff": 0,
+ "stoploss": 0,
+ "trailing_stoploss": 0,
+ "meta": "{\"app_id\":12617,\"gtt\":105099}",
+ "guid": "",
+ "timestamp": "2019-09-09 15:15:08",
+ "triggered_at": 103.7,
+ "order_result": {
+ "status": "failed",
+ "order_id": "",
+ "rejection_reason": "Your order price is lower than the current lower circuit limit of 70.65. Place an order within the daily range."
+ }
+ }
+ }
+ ],
+ "meta": null
+ },
+ {
+ "id": 17531,
+ "user_id": "PH2965",
+ "parent_trigger": null,
+ "type": "two-leg",
+ "created_at": "2019-08-01 15:32:45",
+ "updated_at": "2019-09-04 09:26:18",
+ "expires_at": "2020-08-01 00:00:00",
+ "status": "triggered",
+ "condition": {
+ "exchange": "NSE",
+ "last_price": 1464.6,
+ "tradingsymbol": "ACC",
+ "trigger_values": [
+ 1427.9,
+ 1684.55
+ ]
+ },
+ "orders": [
+ {
+ "account_id": "",
+ "parent_order_id": "",
+ "exchange": "NSE",
+ "tradingsymbol": "ACC",
+ "validity": "",
+ "product": "CNC",
+ "order_type": "LIMIT",
+ "transaction_type": "SELL",
+ "quantity": 6,
+ "disclosed_quantity": 0,
+ "price": 1419.35,
+ "trigger_price": 0,
+ "ltp_atp": "",
+ "squareoff_abs_tick": "",
+ "stoploss_abs_tick": "",
+ "squareoff": 0,
+ "stoploss": 0,
+ "trailing_stoploss": 0,
+ "meta": "",
+ "guid": "",
+ "result": {
+ "account_id": "PH2965",
+ "parent_order_id": "",
+ "exchange": "NSE",
+ "tradingsymbol": "ACC",
+ "validity": "DAY",
+ "product": "CNC",
+ "order_type": "LIMIT",
+ "transaction_type": "SELL",
+ "quantity": 6,
+ "disclosed_quantity": 0,
+ "price": 1419.35,
+ "trigger_price": 0,
+ "ltp_atp": "LTP",
+ "squareoff_abs_tick": "absolute",
+ "stoploss_abs_tick": "absolute",
+ "squareoff": 0,
+ "stoploss": 0,
+ "trailing_stoploss": 0,
+ "meta": "{\"app_id\":12617,\"gtt\":17531}",
+ "guid": "",
+ "timestamp": "2019-09-04 09:26:18",
+ "triggered_at": 1427.5,
+ "order_result": {
+ "status": "success",
+ "order_id": "190904000274307",
+ "rejection_reason": ""
+ }
+ }
+ },
+ {
+ "account_id": "",
+ "parent_order_id": "",
+ "exchange": "NSE",
+ "tradingsymbol": "ACC",
+ "validity": "",
+ "product": "CNC",
+ "order_type": "LIMIT",
+ "transaction_type": "SELL",
+ "quantity": 6,
+ "disclosed_quantity": 0,
+ "price": 1684.8,
+ "trigger_price": 0,
+ "ltp_atp": "",
+ "squareoff_abs_tick": "",
+ "stoploss_abs_tick": "",
+ "squareoff": 0,
+ "stoploss": 0,
+ "trailing_stoploss": 0,
+ "meta": "",
+ "guid": "",
+ "result": null
+ }
+ ],
+ "meta": {}
+ }
+ ]
+}
\ No newline at end of file
diff --git a/tests/mock_responses/gtt_modify_order.json b/tests/mock_responses/gtt_modify_order.json
new file mode 100644
index 0000000..b6fccbd
--- /dev/null
+++ b/tests/mock_responses/gtt_modify_order.json
@@ -0,0 +1 @@
+{"status":"success","data":{"trigger_id":123}}
\ No newline at end of file
diff --git a/tests/mock_responses/gtt_place_order.json b/tests/mock_responses/gtt_place_order.json
new file mode 100644
index 0000000..b6fccbd
--- /dev/null
+++ b/tests/mock_responses/gtt_place_order.json
@@ -0,0 +1 @@
+{"status":"success","data":{"trigger_id":123}}
\ No newline at end of file
diff --git a/tests/mock_responses/historical_minute.json b/tests/mock_responses/historical_minute.json
new file mode 100644
index 0000000..148dd2f
--- /dev/null
+++ b/tests/mock_responses/historical_minute.json
@@ -0,0 +1,25 @@
+{
+ "status": "success",
+ "data": {
+ "candles": [
+ [
+ "2017-12-15T09:15:00+0530",
+ 1704.5,
+ 1705,
+ 1699.25,
+ 1702.8,
+ 2499,
+ 0
+ ],
+ [
+ "2017-12-15T09:16:00+0530",
+ 1702,
+ 1702,
+ 1698.15,
+ 1698.15,
+ 1271,
+ 0
+ ]
+ ]
+ }
+}
diff --git a/tests/mock_responses/holdings.json b/tests/mock_responses/holdings.json
new file mode 100644
index 0000000..a9b6449
--- /dev/null
+++ b/tests/mock_responses/holdings.json
@@ -0,0 +1,822 @@
+{
+ "status": "success",
+ "data": [
+ {
+ "tradingsymbol": "BENGALASM",
+ "exchange": "BSE",
+ "instrument_token": 136472324,
+ "isin": "INE083K01017",
+ "product": "CNC",
+ "price": 0,
+ "quantity": 1,
+ "t1_quantity": 0,
+ "realised_quantity": 1,
+ "collateral_quantity": 0,
+ "collateral_type": "",
+ "average_price": 1150,
+ "last_price": 2620,
+ "close_price": 2751.1,
+ "pnl": 1470,
+ "day_change": -131.0999999999999,
+ "day_change_percentage": -4.7653665806404675
+ },
+ {
+ "tradingsymbol": "CONFIPET",
+ "exchange": "BSE",
+ "instrument_token": 134868228,
+ "isin": "INE552D01024",
+ "product": "CNC",
+ "price": 0,
+ "quantity": 1,
+ "t1_quantity": 0,
+ "realised_quantity": 1,
+ "collateral_quantity": 0,
+ "collateral_type": "",
+ "average_price": 5.89,
+ "last_price": 31.35,
+ "close_price": 31.5,
+ "pnl": 25.46,
+ "day_change": -0.14999999999999858,
+ "day_change_percentage": -0.4761904761904716
+ },
+ {
+ "tradingsymbol": "IPOWER",
+ "exchange": "BSE",
+ "instrument_token": 131175684,
+ "isin": "INE468F01010",
+ "product": "CNC",
+ "price": 0,
+ "quantity": 1,
+ "t1_quantity": 0,
+ "realised_quantity": 1,
+ "collateral_quantity": 0,
+ "collateral_type": "",
+ "average_price": 0,
+ "last_price": 1.95,
+ "close_price": 0,
+ "pnl": 1.95,
+ "day_change": 0,
+ "day_change_percentage": 0
+ },
+ {
+ "tradingsymbol": "JCTLTD",
+ "exchange": "BSE",
+ "instrument_token": 128057092,
+ "isin": "INE945A01026",
+ "product": "CNC",
+ "price": 0,
+ "quantity": 1,
+ "t1_quantity": 0,
+ "realised_quantity": 1,
+ "collateral_quantity": 0,
+ "collateral_type": "",
+ "average_price": 6.03,
+ "last_price": 3.5,
+ "close_price": 3.48,
+ "pnl": -2.5300000000000002,
+ "day_change": 0.020000000000000018,
+ "day_change_percentage": 0.5747126436781614
+ },
+ {
+ "tradingsymbol": "SPICEJET",
+ "exchange": "BSE",
+ "instrument_token": 128072964,
+ "isin": "INE285B01017",
+ "product": "CNC",
+ "price": 0,
+ "quantity": 5,
+ "t1_quantity": 0,
+ "realised_quantity": 5,
+ "collateral_quantity": 0,
+ "collateral_type": "",
+ "average_price": 61.2,
+ "last_price": 145.65,
+ "close_price": 146.05,
+ "pnl": 422.25,
+ "day_change": -0.4000000000000057,
+ "day_change_percentage": -0.2738788086271864
+ },
+ {
+ "tradingsymbol": "ADANIENT",
+ "exchange": "NSE",
+ "instrument_token": 6401,
+ "isin": "INE423A01024",
+ "product": "CNC",
+ "price": 0,
+ "quantity": 2,
+ "t1_quantity": 0,
+ "realised_quantity": 2,
+ "collateral_quantity": 0,
+ "collateral_type": "",
+ "average_price": 77.375,
+ "last_price": 165.25,
+ "close_price": 165.95,
+ "pnl": 175.75,
+ "day_change": -0.6999999999999886,
+ "day_change_percentage": -0.42181379933714286
+ },
+ {
+ "tradingsymbol": "ADANIPORTS",
+ "exchange": "NSE",
+ "instrument_token": 3861249,
+ "isin": "INE742F01042",
+ "product": "CNC",
+ "price": 0,
+ "quantity": 2,
+ "t1_quantity": 0,
+ "realised_quantity": 2,
+ "collateral_quantity": 0,
+ "collateral_type": "",
+ "average_price": 238.875,
+ "last_price": 398.7,
+ "close_price": 404.2,
+ "pnl": 319.65,
+ "day_change": -5.5,
+ "day_change_percentage": -1.3607125185551707
+ },
+ {
+ "tradingsymbol": "ADANIPOWER",
+ "exchange": "NSE",
+ "instrument_token": 4451329,
+ "isin": "INE814H01011",
+ "product": "CNC",
+ "price": 0,
+ "quantity": 2,
+ "t1_quantity": 0,
+ "realised_quantity": 2,
+ "collateral_quantity": 0,
+ "collateral_type": "",
+ "average_price": 32,
+ "last_price": 40.7,
+ "close_price": 40.65,
+ "pnl": 17.400000000000006,
+ "day_change": 0.05000000000000426,
+ "day_change_percentage": 0.12300123001231063
+ },
+ {
+ "tradingsymbol": "APOLLOTYRE",
+ "exchange": "NSE",
+ "instrument_token": 41729,
+ "isin": "INE438A01022",
+ "product": "CNC",
+ "price": 0,
+ "quantity": 4,
+ "t1_quantity": 0,
+ "realised_quantity": 4,
+ "collateral_quantity": 0,
+ "collateral_type": "",
+ "average_price": 206.9,
+ "last_price": 268.8,
+ "close_price": 268.85,
+ "pnl": 247.60000000000002,
+ "day_change": -0.05000000000001137,
+ "day_change_percentage": -0.018597731076812854
+ },
+ {
+ "tradingsymbol": "ASHOKLEY",
+ "exchange": "NSE",
+ "instrument_token": 54273,
+ "isin": "INE208A01029",
+ "product": "CNC",
+ "price": 0,
+ "quantity": 3,
+ "t1_quantity": 0,
+ "realised_quantity": 3,
+ "collateral_quantity": 0,
+ "collateral_type": "",
+ "average_price": 103.08333333333299,
+ "last_price": 117.7,
+ "close_price": 118.6,
+ "pnl": 43.850000000001046,
+ "day_change": -0.8999999999999915,
+ "day_change_percentage": -0.7588532883642424
+ },
+ {
+ "tradingsymbol": "AXISBANK",
+ "exchange": "NSE",
+ "instrument_token": 1510401,
+ "isin": "INE238A01034",
+ "product": "CNC",
+ "price": 0,
+ "quantity": 11,
+ "t1_quantity": 0,
+ "realised_quantity": 11,
+ "collateral_quantity": 0,
+ "collateral_type": "",
+ "average_price": 460.227272727273,
+ "last_price": 546.85,
+ "close_price": 554.6,
+ "pnl": 952.8499999999975,
+ "day_change": -7.75,
+ "day_change_percentage": -1.3974035340786153
+ },
+ {
+ "tradingsymbol": "CIPLA",
+ "exchange": "NSE",
+ "instrument_token": 177665,
+ "isin": "INE059A01026",
+ "product": "CNC",
+ "price": 0,
+ "quantity": 1,
+ "t1_quantity": 0,
+ "realised_quantity": 1,
+ "collateral_quantity": 0,
+ "collateral_type": "",
+ "average_price": 546.6,
+ "last_price": 606.05,
+ "close_price": 612.65,
+ "pnl": 59.44999999999993,
+ "day_change": -6.600000000000023,
+ "day_change_percentage": -1.0772871949726637
+ },
+ {
+ "tradingsymbol": "DBCORP",
+ "exchange": "NSE",
+ "instrument_token": 4577537,
+ "isin": "INE950I01011",
+ "product": "CNC",
+ "price": 0,
+ "quantity": 2,
+ "t1_quantity": 0,
+ "realised_quantity": 2,
+ "collateral_quantity": 0,
+ "collateral_type": "",
+ "average_price": 351,
+ "last_price": 353.7,
+ "close_price": 346.7,
+ "pnl": 5.399999999999977,
+ "day_change": 7,
+ "day_change_percentage": 2.0190366310931642
+ },
+ {
+ "tradingsymbol": "DHANBANK",
+ "exchange": "NSE",
+ "instrument_token": 2907905,
+ "isin": "INE680A01011",
+ "product": "CNC",
+ "price": 0,
+ "quantity": 1,
+ "t1_quantity": 0,
+ "realised_quantity": 1,
+ "collateral_quantity": 0,
+ "collateral_type": "",
+ "average_price": 24.7,
+ "last_price": 29.95,
+ "close_price": 29.8,
+ "pnl": 5.25,
+ "day_change": 0.14999999999999858,
+ "day_change_percentage": 0.5033557046979817
+ },
+ {
+ "tradingsymbol": "DMART",
+ "exchange": "NSE",
+ "instrument_token": 5097729,
+ "isin": "INE192R01011",
+ "product": "CNC",
+ "price": 0,
+ "quantity": 2,
+ "t1_quantity": 0,
+ "realised_quantity": 2,
+ "collateral_quantity": 0,
+ "collateral_type": "",
+ "average_price": 889.95,
+ "last_price": 1148.35,
+ "close_price": 1146.35,
+ "pnl": 516.7999999999997,
+ "day_change": 2,
+ "day_change_percentage": 0.17446678588563705
+ },
+ {
+ "tradingsymbol": "DQE-BE",
+ "exchange": "NSE",
+ "instrument_token": 6211329,
+ "isin": "INE656K01010",
+ "product": "CNC",
+ "price": 0,
+ "quantity": 1,
+ "t1_quantity": 0,
+ "realised_quantity": 1,
+ "collateral_quantity": 0,
+ "collateral_type": "",
+ "average_price": 35.7,
+ "last_price": 18.45,
+ "close_price": 18.45,
+ "pnl": -17.250000000000004,
+ "day_change": 0,
+ "day_change_percentage": 0
+ },
+ {
+ "tradingsymbol": "FINCABLES",
+ "exchange": "NSE",
+ "instrument_token": 265729,
+ "isin": "INE235A01022",
+ "product": "CNC",
+ "price": 0,
+ "quantity": 2,
+ "t1_quantity": 0,
+ "realised_quantity": 2,
+ "collateral_quantity": 0,
+ "collateral_type": "",
+ "average_price": 411.55,
+ "last_price": 699.45,
+ "close_price": 706.25,
+ "pnl": 575.8000000000001,
+ "day_change": -6.7999999999999545,
+ "day_change_percentage": -0.9628318584070731
+ },
+ {
+ "tradingsymbol": "FSL",
+ "exchange": "NSE",
+ "instrument_token": 3661825,
+ "isin": "INE684F01012",
+ "product": "CNC",
+ "price": 0,
+ "quantity": 17,
+ "t1_quantity": 0,
+ "realised_quantity": 17,
+ "collateral_quantity": 0,
+ "collateral_type": "",
+ "average_price": 36.8,
+ "last_price": 40.5,
+ "close_price": 40.15,
+ "pnl": 62.90000000000005,
+ "day_change": 0.3500000000000014,
+ "day_change_percentage": 0.8717310087173136
+ },
+ {
+ "tradingsymbol": "GABRIEL",
+ "exchange": "NSE",
+ "instrument_token": 277761,
+ "isin": "INE524A01029",
+ "product": "CNC",
+ "price": 0,
+ "quantity": 6,
+ "t1_quantity": 0,
+ "realised_quantity": 6,
+ "collateral_quantity": 0,
+ "collateral_type": "",
+ "average_price": 107.55,
+ "last_price": 196.15,
+ "close_price": 195.25,
+ "pnl": 531.6,
+ "day_change": 0.9000000000000057,
+ "day_change_percentage": 0.46094750320102723
+ },
+ {
+ "tradingsymbol": "GAIL",
+ "exchange": "NSE",
+ "instrument_token": 1207553,
+ "isin": "INE129A01019",
+ "product": "CNC",
+ "price": 0,
+ "quantity": 1,
+ "t1_quantity": 0,
+ "realised_quantity": 1,
+ "collateral_quantity": 0,
+ "collateral_type": "",
+ "average_price": 454.7,
+ "last_price": 511.2,
+ "close_price": 508.1,
+ "pnl": 56.5,
+ "day_change": 3.099999999999966,
+ "day_change_percentage": 0.6101161188742307
+ },
+ {
+ "tradingsymbol": "GVKPIL-BE",
+ "exchange": "NSE",
+ "instrument_token": 3386625,
+ "isin": "INE251H01024",
+ "product": "CNC",
+ "price": 0,
+ "quantity": 20,
+ "t1_quantity": 0,
+ "realised_quantity": 20,
+ "collateral_quantity": 0,
+ "collateral_type": "",
+ "average_price": 5.75,
+ "last_price": 18.15,
+ "close_price": 18.1,
+ "pnl": 247.99999999999997,
+ "day_change": 0.04999999999999716,
+ "day_change_percentage": 0.27624309392263624
+ },
+ {
+ "tradingsymbol": "HDFCBANK",
+ "exchange": "NSE",
+ "instrument_token": 341249,
+ "isin": "INE040A01026",
+ "product": "CNC",
+ "price": 0,
+ "quantity": 2,
+ "t1_quantity": 0,
+ "realised_quantity": 2,
+ "collateral_quantity": 0,
+ "collateral_type": "",
+ "average_price": 1234.5,
+ "last_price": 1878.05,
+ "close_price": 1856.75,
+ "pnl": 1287.1,
+ "day_change": 21.299999999999955,
+ "day_change_percentage": 1.14716574660024
+ },
+ {
+ "tradingsymbol": "HMVL",
+ "exchange": "NSE",
+ "instrument_token": 4918017,
+ "isin": "INE871K01015",
+ "product": "CNC",
+ "price": 0,
+ "quantity": 2,
+ "t1_quantity": 0,
+ "realised_quantity": 2,
+ "collateral_quantity": 0,
+ "collateral_type": "",
+ "average_price": 271.9,
+ "last_price": 250.55,
+ "close_price": 248.35,
+ "pnl": -42.69999999999993,
+ "day_change": 2.200000000000017,
+ "day_change_percentage": 0.8858465874773574
+ },
+ {
+ "tradingsymbol": "ICICIBANK",
+ "exchange": "NSE",
+ "instrument_token": 1270529,
+ "isin": "INE090A01021",
+ "product": "CNC",
+ "price": 0,
+ "quantity": 1,
+ "t1_quantity": 0,
+ "realised_quantity": 1,
+ "collateral_quantity": 0,
+ "collateral_type": "",
+ "average_price": 309.7,
+ "last_price": 315.3,
+ "close_price": 312.8,
+ "pnl": 5.600000000000023,
+ "day_change": 2.5,
+ "day_change_percentage": 0.7992327365728901
+ },
+ {
+ "tradingsymbol": "ICIL",
+ "exchange": "NSE",
+ "instrument_token": 3068673,
+ "isin": "INE483B01026",
+ "product": "CNC",
+ "price": 0,
+ "quantity": 4,
+ "t1_quantity": 0,
+ "realised_quantity": 4,
+ "collateral_quantity": 0,
+ "collateral_type": "",
+ "average_price": 157.5,
+ "last_price": 125.7,
+ "close_price": 120.25,
+ "pnl": -127.19999999999999,
+ "day_change": 5.450000000000003,
+ "day_change_percentage": 4.532224532224535
+ },
+ {
+ "tradingsymbol": "IDBI",
+ "exchange": "NSE",
+ "instrument_token": 377857,
+ "isin": "INE008A01015",
+ "product": "CNC",
+ "price": 0,
+ "quantity": 3,
+ "t1_quantity": 0,
+ "realised_quantity": 3,
+ "collateral_quantity": 0,
+ "collateral_type": "",
+ "average_price": 59.79999999999999,
+ "last_price": 60.35,
+ "close_price": 60.05,
+ "pnl": 1.650000000000034,
+ "day_change": 0.30000000000000426,
+ "day_change_percentage": 0.4995836802664517
+ },
+ {
+ "tradingsymbol": "INFY",
+ "exchange": "NSE",
+ "instrument_token": 408065,
+ "isin": "INE009A01021",
+ "product": "CNC",
+ "price": 0,
+ "quantity": 1,
+ "t1_quantity": 0,
+ "realised_quantity": 1,
+ "collateral_quantity": 0,
+ "collateral_type": "",
+ "average_price": 967.95,
+ "last_price": 1033.25,
+ "close_price": 1034.25,
+ "pnl": 65.29999999999995,
+ "day_change": -1,
+ "day_change_percentage": -0.09668842156151801
+ },
+ {
+ "tradingsymbol": "ITC",
+ "exchange": "NSE",
+ "instrument_token": 424961,
+ "isin": "INE154A01025",
+ "product": "CNC",
+ "price": 0,
+ "quantity": 1,
+ "t1_quantity": 0,
+ "realised_quantity": 1,
+ "collateral_quantity": 0,
+ "collateral_type": "",
+ "average_price": 274.5,
+ "last_price": 261.85,
+ "close_price": 262.15,
+ "pnl": -12.649999999999977,
+ "day_change": -0.2999999999999545,
+ "day_change_percentage": -0.11443829868394223
+ },
+ {
+ "tradingsymbol": "JKIL",
+ "exchange": "NSE",
+ "instrument_token": 3908097,
+ "isin": "INE576I01022",
+ "product": "CNC",
+ "price": 0,
+ "quantity": 3,
+ "t1_quantity": 0,
+ "realised_quantity": 3,
+ "collateral_quantity": 0,
+ "collateral_type": "",
+ "average_price": 216.1,
+ "last_price": 301.75,
+ "close_price": 308.2,
+ "pnl": 256.95000000000005,
+ "day_change": -6.449999999999989,
+ "day_change_percentage": -2.0927968851395162
+ },
+ {
+ "tradingsymbol": "JPASSOCIAT",
+ "exchange": "NSE",
+ "instrument_token": 2933761,
+ "isin": "INE455F01025",
+ "product": "CNC",
+ "price": 0,
+ "quantity": 11,
+ "t1_quantity": 0,
+ "realised_quantity": 11,
+ "collateral_quantity": 0,
+ "collateral_type": "",
+ "average_price": 8.00909090909091,
+ "last_price": 23.2,
+ "close_price": 21.35,
+ "pnl": 167.1,
+ "day_change": 1.8499999999999979,
+ "day_change_percentage": 8.665105386416851
+ },
+ {
+ "tradingsymbol": "KRIDHANINF",
+ "exchange": "NSE",
+ "instrument_token": 2938881,
+ "isin": "INE524L01026",
+ "product": "CNC",
+ "price": 0,
+ "quantity": 1,
+ "t1_quantity": 0,
+ "realised_quantity": 1,
+ "collateral_quantity": 0,
+ "collateral_type": "",
+ "average_price": 91.75,
+ "last_price": 121.2,
+ "close_price": 122.25,
+ "pnl": 29.450000000000003,
+ "day_change": -1.0499999999999972,
+ "day_change_percentage": -0.85889570552147
+ },
+ {
+ "tradingsymbol": "KSL",
+ "exchange": "NSE",
+ "instrument_token": 4835585,
+ "isin": "INE907A01026",
+ "product": "CNC",
+ "price": 0,
+ "quantity": 2,
+ "t1_quantity": 0,
+ "realised_quantity": 2,
+ "collateral_quantity": 0,
+ "collateral_type": "",
+ "average_price": 289.75,
+ "last_price": 408.4,
+ "close_price": 398.5,
+ "pnl": 237.29999999999995,
+ "day_change": 9.899999999999977,
+ "day_change_percentage": 2.484316185696356
+ },
+ {
+ "tradingsymbol": "KTKBANK",
+ "exchange": "NSE",
+ "instrument_token": 2061825,
+ "isin": "INE614B01018",
+ "product": "CNC",
+ "price": 0,
+ "quantity": 1,
+ "t1_quantity": 0,
+ "realised_quantity": 1,
+ "collateral_quantity": 0,
+ "collateral_type": "",
+ "average_price": 122.05,
+ "last_price": 149.4,
+ "close_price": 151.9,
+ "pnl": 27.35000000000001,
+ "day_change": -2.5,
+ "day_change_percentage": -1.6458196181698483
+ },
+ {
+ "tradingsymbol": "L&TFH",
+ "exchange": "NSE",
+ "instrument_token": 6386689,
+ "isin": "INE498L01015",
+ "product": "CNC",
+ "price": 0,
+ "quantity": 2,
+ "t1_quantity": 0,
+ "realised_quantity": 2,
+ "collateral_quantity": 0,
+ "collateral_type": "",
+ "average_price": 85.075,
+ "last_price": 173.45,
+ "close_price": 176.75,
+ "pnl": 176.74999999999997,
+ "day_change": -3.3000000000000114,
+ "day_change_percentage": -1.8670438472418733
+ },
+ {
+ "tradingsymbol": "NFL",
+ "exchange": "NSE",
+ "instrument_token": 3564801,
+ "isin": "INE870D01012",
+ "product": "CNC",
+ "price": 0,
+ "quantity": 1,
+ "t1_quantity": 0,
+ "realised_quantity": 1,
+ "collateral_quantity": 0,
+ "collateral_type": "",
+ "average_price": 0,
+ "last_price": 69.25,
+ "close_price": 68.25,
+ "pnl": 69.25,
+ "day_change": 1,
+ "day_change_percentage": 1.465201465201465
+ },
+ {
+ "tradingsymbol": "PNB",
+ "exchange": "NSE",
+ "instrument_token": 2730497,
+ "isin": "INE160A01022",
+ "product": "CNC",
+ "price": 0,
+ "quantity": 2,
+ "t1_quantity": 0,
+ "realised_quantity": 2,
+ "collateral_quantity": 0,
+ "collateral_type": "",
+ "average_price": 112.3,
+ "last_price": 170.8,
+ "close_price": 174.1,
+ "pnl": 117.00000000000003,
+ "day_change": -3.299999999999983,
+ "day_change_percentage": -1.8954623779437008
+ },
+ {
+ "tradingsymbol": "PTC",
+ "exchange": "NSE",
+ "instrument_token": 2906881,
+ "isin": "INE877F01012",
+ "product": "CNC",
+ "price": 0,
+ "quantity": 2,
+ "t1_quantity": 0,
+ "realised_quantity": 2,
+ "collateral_quantity": 0,
+ "collateral_type": "",
+ "average_price": 75.125,
+ "last_price": 115.55,
+ "close_price": 116.55,
+ "pnl": 80.85,
+ "day_change": -1,
+ "day_change_percentage": -0.8580008580008579
+ },
+ {
+ "tradingsymbol": "QUICKHEAL",
+ "exchange": "NSE",
+ "instrument_token": 3357697,
+ "isin": "INE306L01010",
+ "product": "CNC",
+ "price": 0,
+ "quantity": 1,
+ "t1_quantity": 0,
+ "realised_quantity": 1,
+ "collateral_quantity": 0,
+ "collateral_type": "",
+ "average_price": 245,
+ "last_price": 318.15,
+ "close_price": 313.2,
+ "pnl": 73.14999999999998,
+ "day_change": 4.949999999999989,
+ "day_change_percentage": 1.5804597701149388
+ },
+ {
+ "tradingsymbol": "RAJRAYON-BE",
+ "exchange": "NSE",
+ "instrument_token": 3577601,
+ "isin": "INE533D01024",
+ "product": "CNC",
+ "price": 0,
+ "quantity": 1,
+ "t1_quantity": 0,
+ "realised_quantity": 1,
+ "collateral_quantity": 0,
+ "collateral_type": "",
+ "average_price": 0.2,
+ "last_price": 0.35,
+ "close_price": 0.35,
+ "pnl": 0.14999999999999997,
+ "day_change": 0,
+ "day_change_percentage": 0
+ },
+ {
+ "tradingsymbol": "RELIANCE",
+ "exchange": "NSE",
+ "instrument_token": 738561,
+ "isin": "INE002A01018",
+ "product": "CNC",
+ "price": 0,
+ "quantity": 160,
+ "t1_quantity": 0,
+ "realised_quantity": 160,
+ "collateral_quantity": 0,
+ "collateral_type": "",
+ "average_price": 513.513924050633,
+ "last_price": 924.2,
+ "close_price": 923.75,
+ "pnl": 65709.77215189872,
+ "day_change": 0.4500000000000455,
+ "day_change_percentage": 0.04871447902571534
+ },
+ {
+ "tradingsymbol": "SAIL",
+ "exchange": "NSE",
+ "instrument_token": 758529,
+ "isin": "INE114A01011",
+ "product": "CNC",
+ "price": 0,
+ "quantity": 1,
+ "t1_quantity": 0,
+ "realised_quantity": 1,
+ "collateral_quantity": 0,
+ "collateral_type": "",
+ "average_price": 61,
+ "last_price": 92.75,
+ "close_price": 91.1,
+ "pnl": 31.75,
+ "day_change": 1.6500000000000057,
+ "day_change_percentage": 1.8111964873765156
+ },
+ {
+ "tradingsymbol": "SBIN",
+ "exchange": "NSE",
+ "instrument_token": 779521,
+ "isin": "INE062A01020",
+ "product": "CNC",
+ "price": 0,
+ "quantity": 50,
+ "t1_quantity": 0,
+ "realised_quantity": 50,
+ "collateral_quantity": 0,
+ "collateral_type": "",
+ "average_price": 263.824,
+ "last_price": 308.4,
+ "close_price": 314.85,
+ "pnl": 2228.7999999999984,
+ "day_change": -6.4500000000000455,
+ "day_change_percentage": -2.0485945688423204
+ },
+ {
+ "tradingsymbol": "SKMEGGPROD",
+ "exchange": "NSE",
+ "instrument_token": 1211393,
+ "isin": "INE411D01015",
+ "product": "CNC",
+ "price": 0,
+ "quantity": 1,
+ "t1_quantity": 0,
+ "realised_quantity": 1,
+ "collateral_quantity": 0,
+ "collateral_type": "",
+ "average_price": 181.4,
+ "last_price": 96.95,
+ "close_price": 97.15,
+ "pnl": -84.45,
+ "day_change": -0.20000000000000284,
+ "day_change_percentage": -0.20586721564591132
+ }
+ ]
+}
diff --git a/tests/mock_responses/instruments_all.csv b/tests/mock_responses/instruments_all.csv
new file mode 100644
index 0000000..3efe3ed
--- /dev/null
+++ b/tests/mock_responses/instruments_all.csv
@@ -0,0 +1,100 @@
+instrument_token,exchange_token,tradingsymbol,name,last_price,expiry,strike,tick_size,lot_size,instrument_type,segment,exchange
+3813889,14898,CENTRALBK-BE,CENTRAL BANK OF INDIA,0.0,,0.0,0.05,1,EQ,NSE,NSE
+4645121,18145,EMMBI-BL,EMMBI INDUSTRIES,0.0,,0.0,0.05,1,EQ,NSE,NSE
+4531969,17703,MIDCAPIWIN-BL,ICICI PRU MIDCAP IWIN ETF,0.0,,0.0,0.01,1,EQ,NSE,NSE
+5533953,21617,ABCAPITAL-BL,ADITYA BIRLA CAPITAL,0.0,,0.0,0.05,1,EQ,NSE,NSE
+3861249,15083,ADANIPORTS,ADANI PORT & SEZ,0.0,,0.0,0.05,1,EQ,NSE,NSE
+4419329,17263,ARMANFIN,ARMAN FIN SERV,0.0,,0.0,0.05,1,EQ,NSE,NSE
+12073986,47164,BANKNIFTY18JAN23500CE,,2528.4,2018-01-25,23500.0,0.05,40,CE,NFO-OPT,NFO
+13693186,53489,ADANIPORTS17DEC490PE,,80.65,2017-12-28,490.0,0.05,2500,PE,NFO-OPT,NFO
+136483588,533139,FFTF16BGR,FORTIS FIXED TERM FUND - SERIE,0.0,,0.0,0.01,1,EQ,BSE,BSE
+3713281,14505,BALAMINES-BE,BALAJI AMINES,0.0,,0.0,0.05,1,EQ,NSE,NSE
+1373441,5365,BATAINDIA-BE,BATA INDIA DEP RS,0.0,,0.0,0.05,1,EQ,NSE,NSE
+5421569,21178,CDSL-BE,CENTRAL DEPO SER (I),0.0,,0.0,0.05,1,EQ,NSE,NSE
+5421313,21177,CDSL-BL,CENTRAL DEPO SER (I),0.0,,0.0,0.05,1,EQ,NSE,NSE
+1374209,5368,CHENNPETRO-BE,CHENNAI PETRO CORP DE,0.0,,0.0,0.05,1,EQ,NSE,NSE
+3419393,13357,GANGOTRI,GANGOTRI TEXTILES,0.0,,0.0,0.05,1,EQ,NSE,NSE
+2703361,10560,NAVKARCORP-BL,NAVKAR CORPORATION,0.0,,0.0,0.05,1,EQ,NSE,NSE
+5001473,19537,PDPL,PARENTERAL DRUGS,0.0,,0.0,0.05,1,EQ,NSE,NSE
+12074242,47165,BANKNIFTY18JAN23500PE,,35.15,2018-01-25,23500.0,0.05,40,PE,NFO-OPT,NFO
+12074498,47166,BANKNIFTY18JAN23600CE,,2435.55,2018-01-25,23600.0,0.05,40,CE,NFO-OPT,NFO
+5420545,21174,CDSL,CENTRAL DEPO SER (I),0.0,,0.0,0.05,1,EQ,NSE,NSE
+3370497,13166,CELEBRITY-BL,CELEBRITY FASHIONS,0.0,,0.0,0.05,1,EQ,NSE,NSE
+12074754,47167,BANKNIFTY18JAN23600PE,,41.25,2018-01-25,23600.0,0.05,40,PE,NFO-OPT,NFO
+3146497,12291,CENTEXT-BL,CENTURY EXTRUSIONS,0.0,,0.0,0.05,1,EQ,NSE,NSE
+4550145,17774,GROBTEA-BE,THE GROB TEA COMPANY,0.0,,0.0,0.05,1,EQ,NSE,NSE
+21227266,82919,INDIACEM17DEC220PE,,43.45,2017-12-28,220.0,0.05,3500,PE,NFO-OPT,NFO
+6938881,27105,CHROMATIC-BE,CHROMATIC INDIA,0.0,,0.0,0.05,1,EQ,NSE,NSE
+4578305,17884,DBCORP-BL,D.B.CORP,0.0,,0.0,0.05,1,EQ,NSE,NSE
+3155457,12326,DCW-BL,DCW,0.0,,0.0,0.05,1,EQ,NSE,NSE
+5101569,19928,HUDCO-N8,7.64% TAX FREETRI SR2B,0.0,,0.0,0.01,1,EQ,NSE,NSE
+1707521,6670,INFARINDIA,INFAR (INDIA),0.0,,0.0,0.05,1,EQ,NSE,NSE
+21227522,82920,INDIACEM17DEC225CE,,0.4,2017-12-28,225.0,0.05,3500,CE,NFO-OPT,NFO
+21228290,82923,INDIACEM17DEC230PE,,53.1,2017-12-28,230.0,0.05,3500,PE,NFO-OPT,NFO
+136484868,533144,COX&KINGS,COX & KINGS,0.0,,0.0,0.05,1,EQ,BSE,BSE
+12072962,47160,BANKNIFTY18JAN23400CE,,2622.0,2018-01-25,23400.0,0.05,40,CE,NFO-OPT,NFO
+12073474,47162,BANKNIFTY18JAN23400PE,,29.85,2018-01-25,23400.0,0.05,40,PE,NFO-OPT,NFO
+12075010,47168,BANKNIFTY18JAN23700CE,,2343.55,2018-01-25,23700.0,0.05,40,CE,NFO-OPT,NFO
+21227778,82921,INDIACEM17DEC225PE,,48.25,2017-12-28,225.0,0.05,3500,PE,NFO-OPT,NFO
+21228034,82922,INDIACEM17DEC230CE,,0.25,2017-12-28,230.0,0.05,3500,CE,NFO-OPT,NFO
+112655620,440061,828GOI27-ML,828GOI2027,0.0,,0.0,0.25,500000,EQ,BSE,BSE
+136441604,532975,AISHWARYA,AISHWARYA TELECOM,0.0,,0.0,0.01,1,EQ,BSE,BSE
+136483076,533137,DEN,DEN NETWORKS,0.0,,0.0,0.05,1,EQ,BSE,BSE
+136483332,533138,ASTEC,ASTEC LIFESCIENCES,0.0,,0.0,0.05,1,EQ,BSE,BSE
+136485380,533146,DLINKINDIA,D-LINK (INDIA),0.0,,0.0,0.05,1,EQ,BSE,BSE
+1219329,4763,BANKBARODA-BE,BOB - DEPO SETT,0.0,,0.0,0.05,1,EQ,NSE,NSE
+2928385,11439,BANKBEES,RELIANCE ETF BANK BEES,0.0,,0.0,0.01,1,EQ,NSE,NSE
+3715841,14515,BANSWRAS-BE,BANSWARA SYNTEX,0.0,,0.0,0.05,1,EQ,NSE,NSE
+3137281,12255,BERGEPAINT-BL,BERGER PAINTS (I),0.0,,0.0,0.05,1,EQ,NSE,NSE
+3901185,15239,BIRLAMONEY,ADITYA BIRLA MONEY,0.0,,0.0,0.05,1,EQ,NSE,NSE
+1789185,6989,CARRIERAIR-BE,CARRIER AIRCON DEPO,0.0,,0.0,0.05,1,EQ,NSE,NSE
+3123713,12202,CASTEXTECH-BL,CASTEX TECHNOLOGIES,0.0,,0.0,0.05,1,EQ,NSE,NSE
+136485892,533148,JSWENERGY,JSW ENERGY,0.0,,0.0,0.05,1,EQ,BSE,BSE
+136486916,533152,MBLINFRA,MBL INFRASTRUCTURES,0.0,,0.0,0.05,1,EQ,BSE,BSE
+136487172,533153,FDCLTDBBPH,FDC*,0.0,,0.0,0.05,1,EQ,BSE,BSE
+138027524,539170,AXISHB23DD,AXIS MUTUAL FUND,0.0,,0.0,0.01,1,EQ,BSE,BSE
+244332292,954423,RCL14JUL16B,RCL-NIFTY-14-1-19-PVT,0.0,,0.0,0.01,10,EQ,BSE,BSE
+244352260,954501,8HDFCL18,HDFCL-8%-15-1-18-PVT,0.0,,0.0,0.01,1,EQ,BSE,BSE
+244834820,956386,945SREI24,SREI-9.45%-26-5-24-PVT,0.0,,0.0,0.01,1,EQ,BSE,BSE
+5534209,21618,ABCAPITAL-BE,ADITYA BIRLA CAPITAL,0.0,,0.0,0.05,1,EQ,NSE,NSE
+3412225,13329,ERAINFRA-BL,ERA INFRA ENGINEERING,0.0,,0.0,0.05,1,EQ,NSE,NSE
+1884161,7360,SETFNN50-BL,SBI-ETF NIFTY NEXT 50,0.0,,0.0,0.01,1,EQ,NSE,NSE
+3028225,11829,SSWL,STEEL STRIPS WHEELS,0.0,,0.0,0.05,1,EQ,NSE,NSE
+12075266,47169,BANKNIFTY18JAN23700PE,,48.15,2018-01-25,23700.0,0.05,40,PE,NFO-OPT,NFO
+12525058,48926,BANKNIFTY17DEC22500PE,,8.0,2017-12-28,22500.0,0.05,40,PE,NFO-OPT,NFO
+13842434,54072,BANKNIFTY17NOV23600PE,,3.0,2017-11-30,23600.0,0.05,40,PE,NFO-OPT,NFO
+6128129,23938,ESSARPORTS-BE,ESSAR PORTS,0.0,,0.0,0.05,1,EQ,NSE,NSE
+21231874,82937,INDIANB17DEC160PE,,0.05,2017-12-28,160.0,0.05,2000,PE,NFO-OPT,NFO
+136492036,533172,IVZINGOLD,INVESCO INDIA GOLD EXCHANGE TR,0.0,,0.0,0.01,1,EQ,BSE,BSE
+21232386,82939,INDIANB17DEC170PE,,0.05,2017-12-28,170.0,0.05,2000,PE,NFO-OPT,NFO
+13845506,54084,BANKNIFTY17NOV23900PE,,2.25,2017-11-30,23900.0,0.05,40,PE,NFO-OPT,NFO
+136504580,533221,AHLWEST,ASIAN HOTELS (WEST),0.0,,0.0,0.05,1,EQ,BSE,BSE
+4671233,18247,DEEPIND-BL,DEEP INDUSTRIES,0.0,,0.0,0.05,1,EQ,NSE,NSE
+6562305,25634,ESSARSHPNG,ESSAR SHIPPING,0.0,,0.0,0.05,1,EQ,NSE,NSE
+136518404,533275,GAL,GYSCOAL ALLOYS,0.0,,0.0,0.01,1,EQ,BSE,BSE
+3604481,14080,GODREJIND-BE,GODREJ INDUSTRIES,0.0,,0.0,0.05,1,EQ,NSE,NSE
+4527361,17685,GPTINFRA,GPT INFRAPROJECTS,0.0,,0.0,0.05,1,EQ,NSE,NSE
+13845762,54085,BANKNIFTY17NOV24000CE,,1776.2,2017-11-30,24000.0,0.05,40,CE,NFO-OPT,NFO
+211713,827,DEEPAKFERT,DEEPAK FERTILIZERS & PETR,0.0,,0.0,0.05,1,EQ,NSE,NSE
+1256193,4907,ENGINERSIN,ENGINEERS INDIA,0.0,,0.0,0.05,1,EQ,NSE,NSE
+3449089,13473,GTNTEX,GTN TEXTILES,0.0,,0.0,0.05,1,EQ,NSE,NSE
+5003009,19543,HDFCMFGETF,HDFC GOLD ETF,0.0,,0.0,0.05,1,EQ,NSE,NSE
+2166273,8462,DUNCANSIND-BE,DUNCANS INDUSTRIES,0.0,,0.0,0.05,1,EQ,NSE,NSE
+21230850,82933,INDIANB17DEC140PE,,0.05,2017-12-28,140.0,0.05,2000,PE,NFO-OPT,NFO
+21231106,82934,INDIANB17DEC150CE,,262.45,2017-12-28,150.0,0.05,2000,CE,NFO-OPT,NFO
+21231362,82935,INDIANB17DEC150PE,,0.05,2017-12-28,150.0,0.05,2000,PE,NFO-OPT,NFO
+136518660,533276,BSLIMITED,BS,0.0,,0.0,0.01,1,EQ,BSE,BSE
+3798529,14838,DECCANCE,DECCAN CEMENTS,0.0,,0.0,0.05,1,EQ,NSE,NSE
+212481,830,DEEPAKNITR,DEEPAK NITRITE,0.0,,0.0,0.05,1,EQ,NSE,NSE
+3542273,13837,DONEAR-BL,DONEAR IND.,0.0,,0.0,0.05,1,EQ,NSE,NSE
+3862529,15088,EDL,EMPEE DISTI.,0.0,,0.0,0.05,1,EQ,NSE,NSE
+2389505,9334,RAVALSUGAR-BE,RAVALGAONSUGAR FARM,0.0,,0.0,0.05,1,EQ,NSE,NSE
+21231618,82936,INDIANB17DEC160CE,,252.5,2017-12-28,160.0,0.05,2000,CE,NFO-OPT,NFO
+21232130,82938,INDIANB17DEC170CE,,242.55,2017-12-28,170.0,0.05,2000,CE,NFO-OPT,NFO
+112653060,440051,830GOI42-ML,830GOI2042,0.0,,0.0,0.25,500000,EQ,BSE,BSE
+7697153,30067,DUNCANSLTD-BE,DUNCANS INDUSTRIES,0.0,,0.0,0.05,1,EQ,NSE,NSE
+4818433,18822,ENDURANCE,ENDURANCE TECHNO.,0.0,,0.0,0.05,1,EQ,NSE,NSE
+2683649,10483,ENTEGRA,ENTEGRA,0.0,,0.0,0.05,1,EQ,NSE,NSE
+3411713,13327,ERAINFRA,ERA INFRA ENGINEERING,0.0,,0.0,0.05,1,EQ,NSE,NSE
+6563329,25638,ESSARSHPNG-BE,ESSAR SHIPPING,0.0,,0.0,0.05,1,EQ,NSE,NSE
+4352001,17000,GISOLUTION-BE,GI ENGINEERING SOLNS,0.0,,0.0,0.05,1,EQ,NSE,NSE
diff --git a/tests/mock_responses/instruments_nse.csv b/tests/mock_responses/instruments_nse.csv
new file mode 100644
index 0000000..79ee2eb
--- /dev/null
+++ b/tests/mock_responses/instruments_nse.csv
@@ -0,0 +1,100 @@
+instrument_token,exchange_token,tradingsymbol,name,last_price,expiry,strike,tick_size,lot_size,instrument_type,segment,exchange
+3813889,14898,CENTRALBK-BE,CENTRAL BANK OF INDIA,0.0,,0.0,0.05,1,EQ,NSE,NSE
+4645121,18145,EMMBI-BL,EMMBI INDUSTRIES,0.0,,0.0,0.05,1,EQ,NSE,NSE
+4531969,17703,MIDCAPIWIN-BL,ICICI PRU MIDCAP IWIN ETF,0.0,,0.0,0.01,1,EQ,NSE,NSE
+5533953,21617,ABCAPITAL-BL,ADITYA BIRLA CAPITAL,0.0,,0.0,0.05,1,EQ,NSE,NSE
+3861249,15083,ADANIPORTS,ADANI PORT & SEZ,0.0,,0.0,0.05,1,EQ,NSE,NSE
+4419329,17263,ARMANFIN,ARMAN FIN SERV,0.0,,0.0,0.05,1,EQ,NSE,NSE
+3713281,14505,BALAMINES-BE,BALAJI AMINES,0.0,,0.0,0.05,1,EQ,NSE,NSE
+1373441,5365,BATAINDIA-BE,BATA INDIA DEP RS,0.0,,0.0,0.05,1,EQ,NSE,NSE
+5421569,21178,CDSL-BE,CENTRAL DEPO SER (I),0.0,,0.0,0.05,1,EQ,NSE,NSE
+5421313,21177,CDSL-BL,CENTRAL DEPO SER (I),0.0,,0.0,0.05,1,EQ,NSE,NSE
+1374209,5368,CHENNPETRO-BE,CHENNAI PETRO CORP DE,0.0,,0.0,0.05,1,EQ,NSE,NSE
+3419393,13357,GANGOTRI,GANGOTRI TEXTILES,0.0,,0.0,0.05,1,EQ,NSE,NSE
+2703361,10560,NAVKARCORP-BL,NAVKAR CORPORATION,0.0,,0.0,0.05,1,EQ,NSE,NSE
+5001473,19537,PDPL,PARENTERAL DRUGS,0.0,,0.0,0.05,1,EQ,NSE,NSE
+5420545,21174,CDSL,CENTRAL DEPO SER (I),0.0,,0.0,0.05,1,EQ,NSE,NSE
+3370497,13166,CELEBRITY-BL,CELEBRITY FASHIONS,0.0,,0.0,0.05,1,EQ,NSE,NSE
+3146497,12291,CENTEXT-BL,CENTURY EXTRUSIONS,0.0,,0.0,0.05,1,EQ,NSE,NSE
+4550145,17774,GROBTEA-BE,THE GROB TEA COMPANY,0.0,,0.0,0.05,1,EQ,NSE,NSE
+6938881,27105,CHROMATIC-BE,CHROMATIC INDIA,0.0,,0.0,0.05,1,EQ,NSE,NSE
+4578305,17884,DBCORP-BL,D.B.CORP,0.0,,0.0,0.05,1,EQ,NSE,NSE
+3155457,12326,DCW-BL,DCW,0.0,,0.0,0.05,1,EQ,NSE,NSE
+5101569,19928,HUDCO-N8,7.64% TAX FREETRI SR2B,0.0,,0.0,0.01,1,EQ,NSE,NSE
+1707521,6670,INFARINDIA,INFAR (INDIA),0.0,,0.0,0.05,1,EQ,NSE,NSE
+1219329,4763,BANKBARODA-BE,BOB - DEPO SETT,0.0,,0.0,0.05,1,EQ,NSE,NSE
+2928385,11439,BANKBEES,RELIANCE ETF BANK BEES,0.0,,0.0,0.01,1,EQ,NSE,NSE
+3715841,14515,BANSWRAS-BE,BANSWARA SYNTEX,0.0,,0.0,0.05,1,EQ,NSE,NSE
+3137281,12255,BERGEPAINT-BL,BERGER PAINTS (I),0.0,,0.0,0.05,1,EQ,NSE,NSE
+3901185,15239,BIRLAMONEY,ADITYA BIRLA MONEY,0.0,,0.0,0.05,1,EQ,NSE,NSE
+1789185,6989,CARRIERAIR-BE,CARRIER AIRCON DEPO,0.0,,0.0,0.05,1,EQ,NSE,NSE
+3123713,12202,CASTEXTECH-BL,CASTEX TECHNOLOGIES,0.0,,0.0,0.05,1,EQ,NSE,NSE
+5534209,21618,ABCAPITAL-BE,ADITYA BIRLA CAPITAL,0.0,,0.0,0.05,1,EQ,NSE,NSE
+3412225,13329,ERAINFRA-BL,ERA INFRA ENGINEERING,0.0,,0.0,0.05,1,EQ,NSE,NSE
+1884161,7360,SETFNN50-BL,SBI-ETF NIFTY NEXT 50,0.0,,0.0,0.01,1,EQ,NSE,NSE
+3028225,11829,SSWL,STEEL STRIPS WHEELS,0.0,,0.0,0.05,1,EQ,NSE,NSE
+6128129,23938,ESSARPORTS-BE,ESSAR PORTS,0.0,,0.0,0.05,1,EQ,NSE,NSE
+4671233,18247,DEEPIND-BL,DEEP INDUSTRIES,0.0,,0.0,0.05,1,EQ,NSE,NSE
+6562305,25634,ESSARSHPNG,ESSAR SHIPPING,0.0,,0.0,0.05,1,EQ,NSE,NSE
+3604481,14080,GODREJIND-BE,GODREJ INDUSTRIES,0.0,,0.0,0.05,1,EQ,NSE,NSE
+4527361,17685,GPTINFRA,GPT INFRAPROJECTS,0.0,,0.0,0.05,1,EQ,NSE,NSE
+211713,827,DEEPAKFERT,DEEPAK FERTILIZERS & PETR,0.0,,0.0,0.05,1,EQ,NSE,NSE
+1256193,4907,ENGINERSIN,ENGINEERS INDIA,0.0,,0.0,0.05,1,EQ,NSE,NSE
+3449089,13473,GTNTEX,GTN TEXTILES,0.0,,0.0,0.05,1,EQ,NSE,NSE
+5003009,19543,HDFCMFGETF,HDFC GOLD ETF,0.0,,0.0,0.05,1,EQ,NSE,NSE
+2166273,8462,DUNCANSIND-BE,DUNCANS INDUSTRIES,0.0,,0.0,0.05,1,EQ,NSE,NSE
+3798529,14838,DECCANCE,DECCAN CEMENTS,0.0,,0.0,0.05,1,EQ,NSE,NSE
+212481,830,DEEPAKNITR,DEEPAK NITRITE,0.0,,0.0,0.05,1,EQ,NSE,NSE
+3542273,13837,DONEAR-BL,DONEAR IND.,0.0,,0.0,0.05,1,EQ,NSE,NSE
+3862529,15088,EDL,EMPEE DISTI.,0.0,,0.0,0.05,1,EQ,NSE,NSE
+2389505,9334,RAVALSUGAR-BE,RAVALGAONSUGAR FARM,0.0,,0.0,0.05,1,EQ,NSE,NSE
+7697153,30067,DUNCANSLTD-BE,DUNCANS INDUSTRIES,0.0,,0.0,0.05,1,EQ,NSE,NSE
+4818433,18822,ENDURANCE,ENDURANCE TECHNO.,0.0,,0.0,0.05,1,EQ,NSE,NSE
+2683649,10483,ENTEGRA,ENTEGRA,0.0,,0.0,0.05,1,EQ,NSE,NSE
+3411713,13327,ERAINFRA,ERA INFRA ENGINEERING,0.0,,0.0,0.05,1,EQ,NSE,NSE
+6563329,25638,ESSARSHPNG-BE,ESSAR SHIPPING,0.0,,0.0,0.05,1,EQ,NSE,NSE
+4352001,17000,GISOLUTION-BE,GI ENGINEERING SOLNS,0.0,,0.0,0.05,1,EQ,NSE,NSE
+1934849,7558,GONTERPEIP-BE,GONTERMANN PEIPERS DEPO,0.0,,0.0,0.05,1,EQ,NSE,NSE
+2185985,8539,GTNIND-BE,GTN INDUSTRIES,0.0,,0.0,0.05,1,EQ,NSE,NSE
+3179009,12418,GUFICBIO-BL,GUFIC BIOSCIENCES,0.0,,0.0,0.05,1,EQ,NSE,NSE
+4915969,19203,SGBNOV24-GB,2.50% GOLDBONDS2024 TR-VI,0.0,,0.0,0.01,1,EQ,NSE,NSE
+5401857,21101,STARCEMENT-BE,STAR CEMENT,0.0,,0.0,0.05,1,EQ,NSE,NSE
+5533185,21614,ABCAPITAL,ADITYA BIRLA CAPITAL,0.0,,0.0,0.05,1,EQ,NSE,NSE
+3372545,13174,BALKRISIND-BL,BALKRISHNA IND.,0.0,,0.0,0.05,1,EQ,NSE,NSE
+2160129,8438,DATAPROINF-BE,DATAPROINFO - ROLL SETT,0.0,,0.0,0.05,1,EQ,NSE,NSE
+7590401,29650,HUDCO-N7,BOND 7.19% PA TAX FREE S2,0.0,,0.0,0.01,1,EQ,NSE,NSE
+3914497,15291,HERCULES-BL,HERCULES HOI.,0.0,,0.0,0.05,1,EQ,NSE,NSE
+4365313,17052,HARITASEAT,HARITA SEATING SYS.,0.0,,0.0,0.05,1,EQ,NSE,NSE
+3183361,12435,HERITGFOOD-BL,HERITAGE FOODS,0.0,,0.0,0.05,1,EQ,NSE,NSE
+1806849,7058,HESTERBIO-BL,HESTER BIOSCIENCES,0.0,,0.0,0.05,1,EQ,NSE,NSE
+4895233,19122,HIGHGROUND-BE,HIGH GROUND ENTP,0.0,,0.0,0.05,1,EQ,NSE,NSE
+3508225,13704,HINDZINC-BL,HINDUSTAN ZINC,0.0,,0.0,0.05,1,EQ,NSE,NSE
+1804289,7048,HESTERBIO,HESTER BIOSCIENCES,0.0,,0.0,0.05,1,EQ,NSE,NSE
+4894977,19121,HIGHGROUND-BL,HIGH GROUND ENTP,0.0,,0.0,0.05,1,EQ,NSE,NSE
+3188225,12454,HIL-BL,HIL,0.0,,0.0,0.05,1,EQ,NSE,NSE
+3745537,14631,HILTON-BE,HILTON METAL FORGING,0.0,,0.0,0.05,1,EQ,NSE,NSE
+4593409,17943,HINDCOPPER-BE,HINDUSTAN COPPER,0.0,,0.0,0.05,1,EQ,NSE,NSE
+4364801,17050,HINDNATGLS-BE,HIND NATL GLASS & IND,0.0,,0.0,0.05,1,EQ,NSE,NSE
+4767233,18622,IBULHSGFIN-N7,SEC RED NCD SR. IV,0.0,,0.0,0.01,1,EQ,NSE,NSE
+7589889,29648,HUDCO-N6,BOND 7.03% PA TAX FREE S1,0.0,,0.0,0.01,1,EQ,NSE,NSE
+5110273,19962,HUDCO-NA,8.14% TAX FREETRI SR1A,0.0,,0.0,0.01,1,EQ,NSE,NSE
+3790593,14807,HDIL-BE,HOUSING DEV & INFRA,0.0,,0.0,0.05,1,EQ,NSE,NSE
+3914753,15292,HERCULES-BE,HERCULES HOI.,0.0,,0.0,0.05,1,EQ,NSE,NSE
+4774913,18652,ICICIPRULI,ICICI PRU LIFE INS CO,0.0,,0.0,0.05,1,EQ,NSE,NSE
+3607041,14090,IGPL-BE,I G PETROCHEMICALS,0.0,,0.0,0.05,1,EQ,NSE,NSE
+3606017,14086,IGPL,I G PETROCHEMICALS,0.0,,0.0,0.05,1,EQ,NSE,NSE
+3718401,14525,ICRA-BL,ICRA,0.0,,0.0,0.05,1,EQ,NSE,NSE
+3489793,13632,ICSA,ICSA (INDIA),0.0,,0.0,0.05,1,EQ,NSE,NSE
+3189761,12460,IDBI-BL,IDBI BANK,0.0,,0.0,0.05,1,EQ,NSE,NSE
+2795521,10920,IDFCBANK-NE,BOND 0% 2022 TR-3 SR-II,0.0,,0.0,0.01,1,EQ,NSE,NSE
+2883073,11262,IGL,INDRAPRASTHA GAS,0.0,,0.0,0.05,1,EQ,NSE,NSE
+5357825,20929,JALAN-SM,JALAN TRANSOLU. INDIA,0.0,,0.0,0.05,1,EQ,NSE,NSE
+1388801,5425,JBFIND-BE,JBF INDUS -DEP-LS ML,0.0,,0.0,0.05,1,EQ,NSE,NSE
+3083265,12044,JCHAC-BL,JOHNSON CONTROLS HITACHI,0.0,,0.0,0.05,1,EQ,NSE,NSE
+3857153,15067,JCTEL-BL,JCT ELE.,0.0,,0.0,0.05,1,EQ,NSE,NSE
+2997505,11709,JETAIRWAYS,JET AIRWAYS (INDIA),0.0,,0.0,0.05,1,EQ,NSE,NSE
+3513089,13723,JHS-BE,JHS SVEND. LAB.,0.0,,0.0,0.05,1,EQ,NSE,NSE
+3006209,11743,JINDALPHOT,JINDAL PHOTO,0.0,,0.0,0.05,1,EQ,NSE,NSE
+4400641,17190,SHRIPISTON-BE,SHRIRAM PIST. & RING,0.0,,0.0,0.05,1,EQ,NSE,NSE
+2122497,8291,SHRIYAMSEC-BE,SHRIYAM SEC & FIN,0.0,,0.0,0.05,1,EQ,NSE,NSE
+510209,1993,IRFC-ND,BOND 8.44% PA TF TII-SIB,0.0,,0.0,0.01,1,EQ,NSE,NSE
diff --git a/tests/mock_responses/ltp.json b/tests/mock_responses/ltp.json
new file mode 100644
index 0000000..05d9d48
--- /dev/null
+++ b/tests/mock_responses/ltp.json
@@ -0,0 +1,14 @@
+{
+ "status": "success",
+ "data": {
+ "NSE:INFY": {
+ "instrument_token": 408065,
+ "last_price": 1074.35
+ },
+ "NSE:SBIN": {
+ "instrument_token": 408065,
+ "last_price": 1074.35
+ }
+
+ }
+}
diff --git a/tests/mock_responses/margins.json b/tests/mock_responses/margins.json
new file mode 100644
index 0000000..e2b9fa8
--- /dev/null
+++ b/tests/mock_responses/margins.json
@@ -0,0 +1,47 @@
+{
+ "status": "success",
+ "data": {
+ "equity": {
+ "enabled": true,
+ "net": 15481.524,
+ "available": {
+ "adhoc_margin": 0,
+ "cash": 9929.024,
+ "collateral": 5554.5,
+ "intraday_payin": 0
+ },
+ "utilised": {
+ "debits": 2,
+ "exposure": 0,
+ "m2m_realised": -2,
+ "m2m_unrealised": 0,
+ "option_premium": 0,
+ "payout": 0,
+ "span": 0,
+ "holding_sales": 0,
+ "turnover": 0
+ }
+ },
+ "commodity": {
+ "enabled": true,
+ "net": 29675.93,
+ "available": {
+ "adhoc_margin": 0,
+ "cash": 29249.93,
+ "collateral": 0,
+ "intraday_payin": 0
+ },
+ "utilised": {
+ "debits": -426,
+ "exposure": 0,
+ "m2m_realised": 426,
+ "m2m_unrealised": 0,
+ "option_premium": 0,
+ "payout": 0,
+ "span": 0,
+ "holding_sales": 0,
+ "turnover": 0
+ }
+ }
+ }
+}
diff --git a/tests/mock_responses/mf_holdings.json b/tests/mock_responses/mf_holdings.json
new file mode 100644
index 0000000..115a6bc
--- /dev/null
+++ b/tests/mock_responses/mf_holdings.json
@@ -0,0 +1,41 @@
+{
+ "status": "success",
+ "data": [
+ {
+ "folio": "385080203",
+ "fund": "DSP BlackRock Money Manager Fund",
+ "tradingsymbol": "INF740K01QQ3",
+ "average_price": 2146.131,
+ "last_price": 2277.0708,
+ "pnl": 61.018,
+ "quantity": 0.466
+ },
+ {
+ "folio": "1052046771",
+ "fund": "HDFC TaxSaver - Regular Plan",
+ "tradingsymbol": "INF179K01BB8",
+ "average_price": 345.849,
+ "last_price": 559.081,
+ "pnl": 61963.074,
+ "quantity": 290.59
+ },
+ {
+ "folio": "91022348426",
+ "fund": "Axis Long Term Equity Fund",
+ "tradingsymbol": "INF846K01131",
+ "average_price": 28.779,
+ "last_price": 41.3876,
+ "pnl": 44467.717,
+ "quantity": 3526.834
+ },
+ {
+ "folio": "488155267386",
+ "fund": "Reliance Money Manager Fund",
+ "tradingsymbol": "INF204K01EY0",
+ "average_price": 1002.948,
+ "last_price": 1007.5645,
+ "pnl": 2.304,
+ "quantity": 0.499
+ }
+ ]
+}
diff --git a/tests/mock_responses/mf_instruments.csv b/tests/mock_responses/mf_instruments.csv
new file mode 100644
index 0000000..ec9e6fc
--- /dev/null
+++ b/tests/mock_responses/mf_instruments.csv
@@ -0,0 +1,100 @@
+tradingsymbol,amc,name,purchase_allowed,redemption_allowed,minimum_purchase_amount,purchase_amount_multiplier,minimum_additional_purchase_amount,minimum_redemption_quantity,redemption_quantity_multiplier,dividend_type,scheme_type,plan,settlement_type,last_price,last_price_date
+INF209K01157,BirlaSunLifeMutualFund_MF,Aditya Birla Sun Life Advantage Fund,1,1,1000.0,1.0,1000.0,0.001,0.001,payout,equity,regular,T3,106.8,2017-11-23
+INF209K01165,BirlaSunLifeMutualFund_MF,Aditya Birla Sun Life Advantage Fund,1,1,1000.0,1.0,1000.0,0.001,0.001,growth,equity,regular,T3,436.72,2017-11-23
+INF209K01VG0,BirlaSunLifeMutualFund_MF,Aditya Birla Sun Life Advantage Fund - Direct Plan,1,1,1000.0,1.0,1000.0,0.001,0.001,payout,equity,direct,T3,134.2,2017-11-23
+INF209K01VH8,BirlaSunLifeMutualFund_MF,Aditya Birla Sun Life Advantage Fund - Direct Plan,1,1,1000.0,1.0,1000.0,0.001,0.001,growth,equity,direct,T3,453.46,2017-11-23
+INF209K01BS7,BirlaSunLifeMutualFund_MF,Aditya Birla Sun Life Balanced 95 Fund,1,1,1000.0,1.0,1000.0,0.001,0.001,payout,equity,regular,T3,153.26,2017-11-23
+INF209K01BT5,BirlaSunLifeMutualFund_MF,Aditya Birla Sun Life Balanced 95 Fund,1,1,1000.0,1.0,1000.0,0.001,0.001,growth,equity,regular,T3,758.0,2017-11-23
+INF209K01ZC0,BirlaSunLifeMutualFund_MF,Aditya Birla Sun Life Balanced 95 Fund - Direct Plan,1,1,1000.0,1.0,1000.0,0.001,0.001,growth,equity,direct,T3,796.56,2017-11-23
+INF209KA1LH3,BirlaSunLifeMutualFund_MF,Aditya Birla Sun Life Balanced 95 Fund - Direct Plan,1,1,1000.0,1.0,1000.0,0.001,0.001,payout,equity,direct,T3,219.49,2017-11-23
+INF084M01AB8,BirlaSunLifeMutualFund_MF,Aditya Birla Sun Life Balanced Advantage Fund,1,1,1000.0,1.0,1000.0,0.001,0.001,growth,balanced,regular,T3,50.46,2017-11-23
+INF084M01AC6,BirlaSunLifeMutualFund_MF,Aditya Birla Sun Life Balanced Advantage Fund,1,1,1000.0,1.0,1000.0,0.001,0.001,payout,balanced,regular,T3,22.07,2017-11-23
+INF084M01DJ5,BirlaSunLifeMutualFund_MF,Aditya Birla Sun Life Balanced Advantage Fund - Direct Plan,1,1,1000.0,1.0,1000.0,0.001,0.001,growth,balanced,direct,T3,52.43,2017-11-23
+INF084M01DK3,BirlaSunLifeMutualFund_MF,Aditya Birla Sun Life Balanced Advantage Fund - Direct Plan,1,1,1000.0,1.0,1000.0,0.001,0.001,payout,balanced,direct,T3,23.0,2017-11-23
+INF209K010W9,BirlaSunLifeMutualFund_MF,Aditya Birla Sun Life Banking And Financial Services Fund,1,1,1000.0,1.0,1000.0,0.001,0.001,payout,equity,regular,T3,19.62,2017-11-23
+INF209K011W7,BirlaSunLifeMutualFund_MF,Aditya Birla Sun Life Banking And Financial Services Fund,1,1,1000.0,1.0,1000.0,0.001,0.001,growth,equity,regular,T3,27.94,2017-11-23
+INF209K013W3,BirlaSunLifeMutualFund_MF,Aditya Birla Sun Life Banking And Financial Services Fund - Direct Plan,1,1,1000.0,1.0,1000.0,0.001,0.001,payout,equity,direct,T3,24.55,2017-11-23
+INF209K014W1,BirlaSunLifeMutualFund_MF,Aditya Birla Sun Life Banking And Financial Services Fund - Direct Plan,1,1,1000.0,1.0,1000.0,0.001,0.001,growth,equity,direct,T3,28.99,2017-11-23
+INF209K01BE7,BirlaSunLifeMutualFund_MF,Aditya Birla Sun Life Banking and PSU Debt Fund,1,1,1000.0,1.0,1000.0,0.001,0.001,payout,debt,regular,T1,9.9875,2017-11-23
+INF209K01BF4,BirlaSunLifeMutualFund_MF,Aditya Birla Sun Life Banking and PSU Debt Fund,1,1,1000.0,1.0,1000.0,0.001,0.001,growth,debt,regular,T1,49.8034,2017-11-23
+INF209K01YJ8,BirlaSunLifeMutualFund_MF,Aditya Birla Sun Life Banking and PSU Debt Fund - Direct Plan,1,1,1000.0,1.0,1000.0,0.001,0.001,payout,debt,direct,T1,12.7089,2017-11-23
+INF209K01YK6,BirlaSunLifeMutualFund_MF,Aditya Birla Sun Life Banking and PSU Debt Fund - Direct Plan,1,1,1000.0,1.0,1000.0,0.001,0.001,payout,debt,direct,T1,10.4884,2017-11-23
+INF209K01YL4,BirlaSunLifeMutualFund_MF,Aditya Birla Sun Life Banking and PSU Debt Fund - Direct Plan,1,1,1000.0,1.0,1000.0,0.001,0.001,growth,debt,direct,T1,51.1321,2017-11-23
+INF209K01LQ0,BirlaSunLifeMutualFund_MF,Aditya Birla Sun Life Cash Manager,1,1,1000.0,1.0,1000.0,0.001,0.001,growth,debt,regular,T1,408.9951,2017-11-23
+INF209K01XU7,BirlaSunLifeMutualFund_MF,Aditya Birla Sun Life Cash Manager - Direct Plan,1,1,1000.0,1.0,1000.0,0.001,0.001,growth,debt,direct,T1,425.8148,2017-11-23
+INF209K01RU9,BirlaSunLifeMutualFund_MF,Aditya Birla Sun Life Cash Plus,1,1,5000.0,1.0,1000.0,0.001,0.001,growth,liquid,regular,T1,271.5949,2017-11-23
+INF209K01VA3,BirlaSunLifeMutualFund_MF,Aditya Birla Sun Life Cash Plus - Direct Plan,1,1,1000.0,1.0,1000.0,0.001,0.001,growth,liquid,direct,T1,272.5712,2017-11-23
+INF209K01VD7,BirlaSunLifeMutualFund_MF,Aditya Birla Sun Life Cash Plus - Direct Plan,1,1,1000.0,1.0,1000.0,0.001,0.001,payout,liquid,direct,T1,147.9867,2017-11-23
+INF209K01199,BirlaSunLifeMutualFund_MF,Aditya Birla Sun Life Commodity Equities Fund - Global Agri Plan,1,1,1000.0,1.0,1000.0,0.001,0.001,payout,equity,regular,T6,16.4009,2017-11-23
+INF209K01207,BirlaSunLifeMutualFund_MF,Aditya Birla Sun Life Commodity Equities Fund - Global Agri Plan,1,1,1000.0,1.0,1000.0,0.001,0.001,growth,equity,regular,T6,23.1229,2017-11-23
+INF209K01AH2,BirlaSunLifeMutualFund_MF,Aditya Birla Sun Life Constant Maturity 10 Year Gilt Fund,1,1,1000.0,1.0,1000.0,0.001,0.001,growth,debt,regular,T1,50.6235,2017-11-23
+INF209K01AI0,BirlaSunLifeMutualFund_MF,Aditya Birla Sun Life Constant Maturity 10 Year Gilt Fund,1,1,1000.0,1.0,1000.0,0.001,0.001,payout,debt,regular,T1,12.0695,2017-11-23
+INF209K01XS1,BirlaSunLifeMutualFund_MF,Aditya Birla Sun Life Constant Maturity 10 Year Gilt Fund - Direct Plan,1,1,1000.0,1.0,1000.0,0.001,0.001,growth,debt,direct,T1,50.998,2017-11-23
+INF209KA1K47,BirlaSunLifeMutualFund_MF,Aditya Birla Sun Life Corporate Bond Fund,1,1,1000.0,1.0,1000.0,0.001,0.001,growth,debt,regular,T1,12.6521,2017-11-23
+INF209KA1K54,BirlaSunLifeMutualFund_MF,Aditya Birla Sun Life Corporate Bond Fund,1,1,1000.0,1.0,1000.0,0.001,0.001,payout,debt,regular,T1,11.4171,2017-11-23
+INF209KA1K88,BirlaSunLifeMutualFund_MF,Aditya Birla Sun Life Corporate Bond Fund - Direct Plan,1,1,1000.0,1.0,1000.0,0.001,0.001,growth,debt,direct,T1,12.9524,2017-11-23
+INF209KA1K96,BirlaSunLifeMutualFund_MF,Aditya Birla Sun Life Corporate Bond Fund - Direct Plan,1,1,1000.0,1.0,1000.0,0.001,0.001,payout,debt,direct,T1,11.708,2017-11-23
+INF209K01397,BirlaSunLifeMutualFund_MF,Aditya Birla Sun Life Dividend Yield Plus,1,1,1000.0,1.0,1000.0,0.001,0.001,payout,equity,regular,T3,17.25,2017-11-23
+INF209K01405,BirlaSunLifeMutualFund_MF,Aditya Birla Sun Life Dividend Yield Plus,1,1,1000.0,1.0,1000.0,0.001,0.001,growth,equity,regular,T3,178.4,2017-11-23
+INF209K01Q55,BirlaSunLifeMutualFund_MF,Aditya Birla Sun Life Dividend Yield Plus - Direct Plan,1,1,1000.0,1.0,1000.0,0.001,0.001,payout,equity,direct,T3,26.66,2017-11-23
+INF209K01WA1,BirlaSunLifeMutualFund_MF,Aditya Birla Sun Life Dividend Yield Plus - Direct Plan,1,1,1000.0,1.0,1000.0,0.001,0.001,growth,equity,direct,T3,185.33,2017-11-23
+INF209K01793,BirlaSunLifeMutualFund_MF,Aditya Birla Sun Life Dynamic Bond Fund,1,1,1000.0,1.0,1000.0,0.001,0.001,growth,debt,regular,T1,30.0556,2017-11-23
+INF209K01801,BirlaSunLifeMutualFund_MF,Aditya Birla Sun Life Dynamic Bond Fund,1,1,1000.0,1.0,1000.0,0.001,0.001,payout,debt,regular,T1,10.9249,2017-11-23
+INF209K01819,BirlaSunLifeMutualFund_MF,Aditya Birla Sun Life Dynamic Bond Fund,1,1,1000.0,1.0,1000.0,0.001,0.001,payout,debt,regular,T1,10.1744,2017-11-23
+INF209KA1TV7,BirlaSunLifeMutualFund_MF,Aditya Birla Sun Life Dynamic Bond Fund,1,1,1000.0,1.0,1000.0,0.001,0.001,payout,equity,regular,T1,12.1802,2017-11-23
+INF209K01N82,BirlaSunLifeMutualFund_MF,Aditya Birla Sun Life Dynamic Bond Fund - Direct Plan,1,1,1000.0,1.0,1000.0,0.001,0.001,growth,debt,direct,T1,30.8721,2017-11-23
+INF209K01R62,BirlaSunLifeMutualFund_MF,Aditya Birla Sun Life Dynamic Bond Fund - Direct Plan,1,1,1000.0,1.0,1000.0,0.001,0.001,payout,debt,direct,T1,11.1149,2017-11-23
+INF209K01R88,BirlaSunLifeMutualFund_MF,Aditya Birla Sun Life Dynamic Bond Fund - Direct Plan,1,1,1000.0,1.0,1000.0,0.001,0.001,payout,debt,direct,T1,10.4108,2017-11-23
+INF209KA1TX3,BirlaSunLifeMutualFund_MF,Aditya Birla Sun Life Dynamic Bond Fund - Direct Plan,1,1,1000.0,1.0,1000.0,0.001,0.001,payout,debt,direct,T1,12.4196,2017-11-23
+INF209K01256,BirlaSunLifeMutualFund_MF,Aditya Birla Sun Life Enhanced Arbitrage Fund,1,1,1000.0,1.0,1000.0,0.001,0.001,payout,equity,regular,T3,10.8783,2017-11-23
+INF209K01264,BirlaSunLifeMutualFund_MF,Aditya Birla Sun Life Enhanced Arbitrage Fund,1,1,1000.0,1.0,1000.0,0.001,0.001,growth,equity,regular,T3,17.5067,2017-11-23
+INF209K01P80,BirlaSunLifeMutualFund_MF,Aditya Birla Sun Life Enhanced Arbitrage Fund - Direct Plan,1,1,1000.0,1.0,1000.0,0.001,0.001,payout,equity,direct,T3,11.0934,2017-11-23
+INF209K01VP1,BirlaSunLifeMutualFund_MF,Aditya Birla Sun Life Enhanced Arbitrage Fund - Direct Plan,1,1,1000.0,1.0,1000.0,0.001,0.001,growth,equity,direct,T3,17.9567,2017-11-23
+INF209K01AJ8,BirlaSunLifeMutualFund_MF,Aditya Birla Sun Life Equity Fund,1,1,1000.0,1.0,1000.0,0.001,0.001,growth,equity,regular,T3,710.7,2017-11-23
+INF209K01AQ3,BirlaSunLifeMutualFund_MF,Aditya Birla Sun Life Equity Fund,1,1,1000.0,1.0,1000.0,0.001,0.001,payout,equity,regular,T3,104.58,2017-11-23
+INF209K01XX1,BirlaSunLifeMutualFund_MF,Aditya Birla Sun Life Equity Fund - Direct Plan,1,1,1000.0,1.0,1000.0,0.001,0.001,growth,equity,direct,T3,742.17,2017-11-23
+INF209KA1TS3,BirlaSunLifeMutualFund_MF,Aditya Birla Sun Life Equity Savings Fund,1,1,1000.0,1.0,1000.0,0.001,0.001,growth,equity,regular,T3,13.1,2017-11-23
+INF209KA1TT1,BirlaSunLifeMutualFund_MF,Aditya Birla Sun Life Equity Savings Fund,1,1,1000.0,1.0,1000.0,0.001,0.001,payout,equity,regular,T3,11.64,2017-11-23
+INF209KA1TP9,BirlaSunLifeMutualFund_MF,Aditya Birla Sun Life Equity Savings Fund - Direct Plan,1,1,1000.0,1.0,1000.0,0.001,0.001,growth,equity,direct,T3,13.54,2017-11-23
+INF209KA1TQ7,BirlaSunLifeMutualFund_MF,Aditya Birla Sun Life Equity Savings Fund - Direct Plan,1,1,1000.0,1.0,1000.0,0.001,0.001,payout,equity,direct,T3,12.27,2017-11-23
+INF084M01101,BirlaSunLifeMutualFund_MF,Aditya Birla Sun Life Financial Planning FoF Aggressive Plan,1,1,1000.0,1.0,1000.0,0.001,0.001,growth,fof,regular,T4,21.9919,2017-11-23
+INF084M01119,BirlaSunLifeMutualFund_MF,Aditya Birla Sun Life Financial Planning FoF Aggressive Plan,1,1,1000.0,1.0,1000.0,0.001,0.001,payout,fof,regular,T4,20.13,2017-11-23
+INF084M01044,BirlaSunLifeMutualFund_MF,Aditya Birla Sun Life Financial Planning FoF Conservative Plan,1,1,1000.0,1.0,1000.0,0.001,0.001,growth,fof,regular,T4,17.3032,2017-11-23
+INF084M01051,BirlaSunLifeMutualFund_MF,Aditya Birla Sun Life Financial Planning FoF Conservative Plan,1,1,1000.0,1.0,1000.0,0.001,0.001,payout,fof,regular,T4,15.744,2017-11-23
+INF084M01077,BirlaSunLifeMutualFund_MF,Aditya Birla Sun Life Financial Planning FoF Prudent Plan,1,1,1000.0,1.0,1000.0,0.001,0.001,growth,fof,regular,T4,19.0899,2017-11-23
+INF084M01085,BirlaSunLifeMutualFund_MF,Aditya Birla Sun Life Financial Planning FoF Prudent Plan,1,1,1000.0,1.0,1000.0,0.001,0.001,payout,fof,regular,T4,17.1217,2017-11-23
+INF209K01MG9,BirlaSunLifeMutualFund_MF,Aditya Birla Sun Life Floating Rate Fund - Long Term Plan,1,1,1000.0,1.0,1000.0,0.001,0.001,growth,debt,regular,T1,208.1037,2017-11-23
+INF209K01UX7,BirlaSunLifeMutualFund_MF,Aditya Birla Sun Life Floating Rate Fund - Long Term Plan - Direct Plan,1,1,1000.0,1.0,1000.0,0.001,0.001,growth,debt,direct,T1,210.3858,2017-11-23
+INF209K01RV7,BirlaSunLifeMutualFund_MF,Aditya Birla Sun Life Floating Rate Fund - Short Term Plan,1,1,1000.0,1.0,1000.0,0.001,0.001,growth,liquid,regular,T1,225.569,2017-11-23
+INF209K01UU3,BirlaSunLifeMutualFund_MF,Aditya Birla Sun Life Floating Rate Fund - Short Term Plan - Direct Plan,1,1,1000.0,1.0,1000.0,0.001,0.001,growth,liquid,direct,T1,226.363,2017-11-23
+INF209K01BO6,BirlaSunLifeMutualFund_MF,Aditya Birla Sun Life Frontline Equity Fund,1,1,1000.0,1.0,1000.0,0.001,0.001,payout,equity,regular,T3,27.34,2017-11-23
+INF209K01BR9,BirlaSunLifeMutualFund_MF,Aditya Birla Sun Life Frontline Equity Fund,1,1,1000.0,1.0,1000.0,0.001,0.001,growth,equity,regular,T3,217.34,2017-11-23
+INF209K01YX9,BirlaSunLifeMutualFund_MF,Aditya Birla Sun Life Frontline Equity Fund - Direct Plan,1,1,1000.0,1.0,1000.0,0.001,0.001,payout,equity,direct,T3,50.73,2017-11-23
+INF209K01YY7,BirlaSunLifeMutualFund_MF,Aditya Birla Sun Life Frontline Equity Fund - Direct Plan,1,1,1000.0,1.0,1000.0,0.001,0.001,growth,equity,direct,T3,227.39,2017-11-23
+INF209K01AC3,BirlaSunLifeMutualFund_MF,Aditya Birla Sun Life Gilt Plus - PF Plan,1,1,1000.0,1.0,1000.0,0.001,0.001,growth,debt,regular,T1,48.6101,2017-11-23
+INF209K01AD1,BirlaSunLifeMutualFund_MF,Aditya Birla Sun Life Gilt Plus - PF Plan,1,1,1000.0,1.0,1000.0,0.001,0.001,growth,debt,regular,T1,48.6101,2017-11-23
+INF209K01AF6,BirlaSunLifeMutualFund_MF,Aditya Birla Sun Life Gilt Plus - PF Plan,1,1,1000.0,1.0,1000.0,0.001,0.001,payout,debt,regular,T1,10.1758,2017-11-23
+INF209K01XP7,BirlaSunLifeMutualFund_MF,Aditya Birla Sun Life Gilt Plus - PF Plan - Direct Plan,1,1,1000.0,1.0,1000.0,0.001,0.001,growth,debt,direct,T1,49.8019,2017-11-23
+INF209K01XQ5,BirlaSunLifeMutualFund_MF,Aditya Birla Sun Life Gilt Plus - PF Plan - Direct Plan,1,1,1000.0,1.0,1000.0,0.001,0.001,growth,debt,direct,T1,49.8019,2017-11-23
+INF209KA1LC4,BirlaSunLifeMutualFund_MF,Aditya Birla Sun Life Gilt Plus - PF Plan - Direct Plan,1,1,1000.0,1.0,1000.0,0.001,0.001,payout,debt,direct,T1,10.3855,2017-11-23
+INF209K01PF4,BirlaSunLifeMutualFund_MF,Aditya Birla Sun Life Gold Fund,1,1,1000.0,1.0,1000.0,0.001,0.001,growth,fof,regular,T3,9.5415,2017-11-23
+INF209K01PG2,BirlaSunLifeMutualFund_MF,Aditya Birla Sun Life Gold Fund,1,1,1000.0,1.0,1000.0,0.001,0.001,payout,fof,regular,T3,9.5402,2017-11-23
+INF209K01YT7,BirlaSunLifeMutualFund_MF,Aditya Birla Sun Life Gold Fund - Direct Plan,1,1,1000.0,1.0,1000.0,0.001,0.001,payout,fof,direct,T3,9.6571,2017-11-23
+INF209K01YU5,BirlaSunLifeMutualFund_MF,Aditya Birla Sun Life Gold Fund - Direct Plan,1,1,1000.0,1.0,1000.0,0.001,0.001,growth,fof,direct,T3,9.6609,2017-11-23
+INF209K01R13,BirlaSunLifeMutualFund_MF,Aditya Birla Sun Life Income Plus - Direct Plan,1,1,1000.0,1.0,1000.0,0.001,0.001,payout,debt,direct,T1,13.3298,2017-11-23
+INF209K01WY1,BirlaSunLifeMutualFund_MF,Aditya Birla Sun Life Income Plus - Direct Plan,1,1,1000.0,1.0,1000.0,0.001,0.001,growth,debt,direct,T1,78.7456,2017-11-23
+INF209KA1WL2,BirlaSunLifeMutualFund_MF,Aditya Birla Sun Life Income Plus - Direct Plan,1,1,1000.0,1.0,1000.0,0.001,0.001,payout,debt,direct,T1,11.621,2017-11-23
+INF209K01579,BirlaSunLifeMutualFund_MF,Aditya Birla Sun Life Income Plus - Regular Plan,1,1,1000.0,1.0,1000.0,0.001,0.001,growth,debt,regular,T1,76.0586,2017-11-23
+INF209K01587,BirlaSunLifeMutualFund_MF,Aditya Birla Sun Life Income Plus - Regular Plan,1,1,1000.0,1.0,1000.0,0.001,0.001,payout,debt,regular,T1,12.7941,2017-11-23
+INF209K01LA4,BirlaSunLifeMutualFund_MF,Aditya Birla Sun Life Index Fund,1,1,1000.0,1.0,1000.0,0.001,0.001,payout,equity,regular,T3,13.3014,2017-11-23
+INF209K01LB2,BirlaSunLifeMutualFund_MF,Aditya Birla Sun Life Index Fund,1,1,1000.0,1.0,1000.0,0.001,0.001,growth,equity,regular,T3,101.4926,2017-11-23
+INF209K01VX5,BirlaSunLifeMutualFund_MF,Aditya Birla Sun Life Index Fund - Direct Plan,1,1,1000.0,1.0,1000.0,0.001,0.001,payout,equity,direct,T3,13.4709,2017-11-23
+INF209K01VY3,BirlaSunLifeMutualFund_MF,Aditya Birla Sun Life Index Fund - Direct Plan,1,1,1000.0,1.0,1000.0,0.001,0.001,growth,equity,direct,T3,101.6988,2017-11-23
+INF209K01439,BirlaSunLifeMutualFund_MF,Aditya Birla Sun Life India GenNext Fund,1,1,1000.0,1.0,1000.0,0.001,0.001,payout,equity,regular,T3,25.71,2017-11-23
+INF209K01447,BirlaSunLifeMutualFund_MF,Aditya Birla Sun Life India GenNext Fund,1,1,1000.0,1.0,1000.0,0.001,0.001,growth,equity,regular,T3,78.3,2017-11-23
+INF209K01Q63,BirlaSunLifeMutualFund_MF,Aditya Birla Sun Life India GenNext Fund - Direct Plan,1,1,1000.0,1.0,1000.0,0.001,0.001,payout,equity,direct,T3,29.23,2017-11-23
+INF209K01WC7,BirlaSunLifeMutualFund_MF,Aditya Birla Sun Life India GenNext Fund - Direct Plan,1,1,1000.0,1.0,1000.0,0.001,0.001,growth,equity,direct,T3,82.08,2017-11-23
+INF209K01280,BirlaSunLifeMutualFund_MF,Aditya Birla Sun Life India Opportunities Fund,1,1,1000.0,1.0,1000.0,0.001,0.001,payout,equity,regular,T3,30.52,2017-11-23
+INF209K01298,BirlaSunLifeMutualFund_MF,Aditya Birla Sun Life India Opportunities Fund,1,1,1000.0,1.0,1000.0,0.001,0.001,growth,equity,regular,T3,146.95,2017-11-23
+INF209K01P98,BirlaSunLifeMutualFund_MF,Aditya Birla Sun Life India Opportunities Fund - Direct Plan,1,1,1000.0,1.0,1000.0,0.001,0.001,payout,equity,direct,T3,42.01,2017-11-23
+INF209K01VR7,BirlaSunLifeMutualFund_MF,Aditya Birla Sun Life India Opportunities Fund - Direct Plan,1,1,1000.0,1.0,1000.0,0.001,0.001,growth,equity,direct,T3,151.59,2017-11-23
diff --git a/tests/mock_responses/mf_orders.json b/tests/mock_responses/mf_orders.json
new file mode 100644
index 0000000..6062c1b
--- /dev/null
+++ b/tests/mock_responses/mf_orders.json
@@ -0,0 +1,47 @@
+{
+ "status": "success",
+ "data": [
+ {
+ "order_id": "867688079445476",
+ "exchange_order_id": "",
+ "tradingsymbol": "INF174K01LS2",
+ "status": "CANCELLED",
+ "status_message": "",
+ "folio": "",
+ "fund": "Kotak Select Focus Fund - Direct Plan",
+ "order_timestamp": "2017-12-28 11:44",
+ "exchange_timestamp": "",
+ "settlement_id": "",
+ "transaction_type": "BUY",
+ "variety": "regular",
+ "purchase_type": "FRESH",
+ "quantity": 0,
+ "amount": 5000,
+ "last_price": 35.135,
+ "average_price": 0,
+ "placed_by": "DA0017",
+ "tag": ""
+ },
+ {
+ "order_id": "396109826218232",
+ "exchange_order_id": "",
+ "tradingsymbol": "INF174K01LS2",
+ "status": "CANCELLED",
+ "status_message": "",
+ "folio": "",
+ "fund": "Kotak Select Focus Fund - Direct Plan",
+ "order_timestamp": "2017-12-28 11:40",
+ "exchange_timestamp": "",
+ "settlement_id": "",
+ "transaction_type": "BUY",
+ "variety": "regular",
+ "purchase_type": "FRESH",
+ "quantity": 0,
+ "amount": 5000,
+ "last_price": 35.135,
+ "average_price": 0,
+ "placed_by": "DA0017",
+ "tag": ""
+ }
+ ]
+}
diff --git a/tests/mock_responses/mf_orders_info.json b/tests/mock_responses/mf_orders_info.json
new file mode 100644
index 0000000..bc77860
--- /dev/null
+++ b/tests/mock_responses/mf_orders_info.json
@@ -0,0 +1,24 @@
+{
+ "status": "success",
+ "data": {
+ "order_id": "460687158435713",
+ "exchange_order_id": "",
+ "tradingsymbol": "INF174K01LS2",
+ "status": "CANCELLED",
+ "status_message": "",
+ "folio": "",
+ "fund": "Kotak Select Focus Fund - Direct Plan",
+ "order_timestamp": "2017-12-29 11:44",
+ "exchange_timestamp": "",
+ "settlement_id": "",
+ "transaction_type": "BUY",
+ "variety": "regular",
+ "purchase_type": "FRESH",
+ "quantity": 0,
+ "amount": 5000,
+ "last_price": 35.135,
+ "average_price": 0,
+ "placed_by": "DA0017",
+ "tag": ""
+ }
+}
diff --git a/tests/mock_responses/mf_sip_info.json b/tests/mock_responses/mf_sip_info.json
new file mode 100644
index 0000000..196e5c6
--- /dev/null
+++ b/tests/mock_responses/mf_sip_info.json
@@ -0,0 +1,19 @@
+{
+ "status": "success",
+ "data": {
+ "sip_id": "1234",
+ "tradingsymbol": "INF090I01239",
+ "fund": "Franklin India Prima Plus",
+ "dividend_type": "growth",
+ "transaction_type": "BUY",
+ "status": "ACTIVE",
+ "created": "2016-01-01 13:00:00",
+ "frequency": "monthly",
+ "instalment_amount": 1000,
+ "instalments": -1,
+ "last_instalment": "2017-07-05 07:33:32",
+ "pending_instalments": -1,
+ "instalment_date": 5,
+ "tag": ""
+ }
+}
diff --git a/tests/mock_responses/mf_sips.json b/tests/mock_responses/mf_sips.json
new file mode 100644
index 0000000..caa1e3c
--- /dev/null
+++ b/tests/mock_responses/mf_sips.json
@@ -0,0 +1,22 @@
+{
+ "status": "success",
+ "data": [
+ {
+ "sip_id": "367614126230235",
+ "tradingsymbol": "INF846K01131",
+ "fund": "Axis Long Term Equity Fund",
+ "dividend_type": "growth",
+ "transaction_type": "BUY",
+ "status": "ACTIVE",
+ "created": "2018-04-30 12:25:00",
+ "frequency": "weekly",
+ "trigger_price": 0,
+ "instalment_amount": 500,
+ "instalments": -1,
+ "last_instalment": "2018-05-14 07:18:56",
+ "pending_instalments": -1,
+ "instalment_day": 0,
+ "tag": ""
+ }
+ ]
+}
diff --git a/tests/mock_responses/ohlc.json b/tests/mock_responses/ohlc.json
new file mode 100644
index 0000000..cb25163
--- /dev/null
+++ b/tests/mock_responses/ohlc.json
@@ -0,0 +1,25 @@
+{
+ "status": "success",
+ "data": {
+ "NSE:INFY": {
+ "instrument_token": 408065,
+ "last_price": 1075,
+ "ohlc": {
+ "open": 1085.8,
+ "high": 1085.9,
+ "low": 1070.9,
+ "close": 1075.8
+ }
+ },
+ "NSE:SBIN": {
+ "instrument_token": 408065,
+ "last_price": 1075,
+ "ohlc": {
+ "open": 1085.8,
+ "high": 1085.9,
+ "low": 1070.9,
+ "close": 1075.8
+ }
+ }
+ }
+}
diff --git a/tests/mock_responses/order_info.json b/tests/mock_responses/order_info.json
new file mode 100644
index 0000000..05d9073
--- /dev/null
+++ b/tests/mock_responses/order_info.json
@@ -0,0 +1,221 @@
+{
+ "status": "success",
+ "data": [
+ {
+ "average_price": 0,
+ "cancelled_quantity": 0,
+ "disclosed_quantity": 0,
+ "exchange": "NSE",
+ "exchange_order_id": null,
+ "exchange_timestamp": null,
+ "filled_quantity": 0,
+ "instrument_token": 1,
+ "order_id": "171229000724687",
+ "order_timestamp": "2017-12-29 11:06:52",
+ "order_type": "LIMIT",
+ "parent_order_id": null,
+ "pending_quantity": 1,
+ "placed_by": "DA0017",
+ "price": 300,
+ "product": "CNC",
+ "quantity": 1,
+ "status": "PUT ORDER REQ RECEIVED",
+ "status_message": null,
+ "tag": null,
+ "tradingsymbol": "SBIN",
+ "transaction_type": "BUY",
+ "trigger_price": 0,
+ "validity": "DAY",
+ "variety": "regular"
+ },
+ {
+ "average_price": 0,
+ "cancelled_quantity": 0,
+ "disclosed_quantity": 0,
+ "exchange": "NSE",
+ "exchange_order_id": null,
+ "exchange_timestamp": null,
+ "filled_quantity": 0,
+ "instrument_token": 779521,
+ "order_id": "171229000724687",
+ "order_timestamp": "2017-12-29 11:06:52",
+ "order_type": "LIMIT",
+ "parent_order_id": null,
+ "pending_quantity": 1,
+ "placed_by": "DA0017",
+ "price": 300,
+ "product": "CNC",
+ "quantity": 1,
+ "status": "VALIDATION PENDING",
+ "status_message": null,
+ "tag": null,
+ "tradingsymbol": "SBIN",
+ "transaction_type": "BUY",
+ "trigger_price": 0,
+ "validity": "DAY",
+ "variety": "regular"
+ },
+ {
+ "average_price": 0,
+ "cancelled_quantity": 0,
+ "disclosed_quantity": 0,
+ "exchange": "NSE",
+ "exchange_order_id": null,
+ "exchange_timestamp": null,
+ "filled_quantity": 0,
+ "instrument_token": 779521,
+ "order_id": "171229000724687",
+ "order_timestamp": "2017-12-29 11:06:52",
+ "order_type": "LIMIT",
+ "parent_order_id": null,
+ "pending_quantity": 1,
+ "placed_by": "DA0017",
+ "price": 300,
+ "product": "CNC",
+ "quantity": 1,
+ "status": "OPEN PENDING",
+ "status_message": null,
+ "tag": null,
+ "tradingsymbol": "SBIN",
+ "transaction_type": "BUY",
+ "trigger_price": 0,
+ "validity": "DAY",
+ "variety": "regular"
+ },
+ {
+ "average_price": 0,
+ "cancelled_quantity": 0,
+ "disclosed_quantity": 0,
+ "exchange": "NSE",
+ "exchange_order_id": "1300000001887410",
+ "exchange_timestamp": "2017-12-29 11:06:52",
+ "filled_quantity": 0,
+ "instrument_token": 779521,
+ "order_id": "171229000724687",
+ "order_timestamp": "2017-12-29 11:06:52",
+ "order_type": "LIMIT",
+ "parent_order_id": null,
+ "pending_quantity": 1,
+ "placed_by": "DA0017",
+ "price": 300,
+ "product": "CNC",
+ "quantity": 1,
+ "status": "OPEN",
+ "status_message": null,
+ "tag": null,
+ "tradingsymbol": "SBIN",
+ "transaction_type": "BUY",
+ "trigger_price": 0,
+ "validity": "DAY",
+ "variety": "regular"
+ },
+ {
+ "average_price": 0,
+ "cancelled_quantity": 0,
+ "disclosed_quantity": 0,
+ "exchange": "NSE",
+ "exchange_order_id": "1300000001887410",
+ "exchange_timestamp": "2017-12-29 11:06:52",
+ "filled_quantity": 0,
+ "instrument_token": 779521,
+ "order_id": "171229000724687",
+ "order_timestamp": "2017-12-29 11:08:16",
+ "order_type": "LIMIT",
+ "parent_order_id": null,
+ "pending_quantity": 1,
+ "placed_by": "DA0017",
+ "price": 300,
+ "product": "CNC",
+ "quantity": 1,
+ "status": "MODIFY VALIDATION PENDING",
+ "status_message": null,
+ "tag": null,
+ "tradingsymbol": "SBIN",
+ "transaction_type": "BUY",
+ "trigger_price": 0,
+ "validity": "DAY",
+ "variety": "regular"
+ },
+ {
+ "average_price": 0,
+ "cancelled_quantity": 0,
+ "disclosed_quantity": 0,
+ "exchange": "NSE",
+ "exchange_order_id": "1300000001887410",
+ "exchange_timestamp": "2017-12-29 11:06:52",
+ "filled_quantity": 0,
+ "instrument_token": 779521,
+ "order_id": "171229000724687",
+ "order_timestamp": "2017-12-29 11:08:16",
+ "order_type": "LIMIT",
+ "parent_order_id": null,
+ "pending_quantity": 1,
+ "placed_by": "DA0017",
+ "price": 300,
+ "product": "CNC",
+ "quantity": 1,
+ "status": "MODIFY PENDING",
+ "status_message": null,
+ "tag": null,
+ "tradingsymbol": "SBIN",
+ "transaction_type": "BUY",
+ "trigger_price": 0,
+ "validity": "DAY",
+ "variety": "regular"
+ },
+ {
+ "average_price": 0,
+ "cancelled_quantity": 0,
+ "disclosed_quantity": 0,
+ "exchange": "NSE",
+ "exchange_order_id": "1300000001887410",
+ "exchange_timestamp": "2017-12-29 11:08:16",
+ "filled_quantity": 0,
+ "instrument_token": 779521,
+ "order_id": "171229000724687",
+ "order_timestamp": "2017-12-29 11:08:16",
+ "order_type": "LIMIT",
+ "parent_order_id": null,
+ "pending_quantity": 1,
+ "placed_by": "DA0017",
+ "price": 300,
+ "product": "CNC",
+ "quantity": 1,
+ "status": "MODIFIED",
+ "status_message": null,
+ "tag": null,
+ "tradingsymbol": "SBIN",
+ "transaction_type": "BUY",
+ "trigger_price": 0,
+ "validity": "DAY",
+ "variety": "regular"
+ },
+ {
+ "average_price": 0,
+ "cancelled_quantity": 0,
+ "disclosed_quantity": 0,
+ "exchange": "NSE",
+ "exchange_order_id": "1300000001887410",
+ "exchange_timestamp": "2017-12-29 11:08:16",
+ "filled_quantity": 0,
+ "instrument_token": 779521,
+ "order_id": "171229000724687",
+ "order_timestamp": "2017-12-29 11:08:16",
+ "order_type": "LIMIT",
+ "parent_order_id": null,
+ "pending_quantity": 1,
+ "placed_by": "DA0017",
+ "price": 300.1,
+ "product": "CNC",
+ "quantity": 1,
+ "status": "OPEN",
+ "status_message": null,
+ "tag": null,
+ "tradingsymbol": "SBIN",
+ "transaction_type": "BUY",
+ "trigger_price": 0,
+ "validity": "DAY",
+ "variety": "regular"
+ }
+ ]
+ }
diff --git a/tests/mock_responses/order_response.json b/tests/mock_responses/order_response.json
new file mode 100644
index 0000000..334b163
--- /dev/null
+++ b/tests/mock_responses/order_response.json
@@ -0,0 +1,6 @@
+{
+ "status": "success",
+ "data": {
+ "order_id": "151220000000000"
+ }
+ }
\ No newline at end of file
diff --git a/tests/mock_responses/order_trades.json b/tests/mock_responses/order_trades.json
new file mode 100644
index 0000000..ded3a44
--- /dev/null
+++ b/tests/mock_responses/order_trades.json
@@ -0,0 +1,19 @@
+{
+ "status": "success",
+ "data": [
+ {
+ "average_price": 310.7,
+ "exchange": "NSE",
+ "exchange_order_id": "1300000001887410",
+ "exchange_timestamp": "2017-12-29 12:02:05",
+ "instrument_token": 779521,
+ "order_id": "171229000724687",
+ "order_timestamp": "12:02:05",
+ "product": "CNC",
+ "quantity": 1,
+ "trade_id": "75894751",
+ "tradingsymbol": "SBIN",
+ "transaction_type": "BUY"
+ }
+ ]
+}
diff --git a/tests/mock_responses/orders.json b/tests/mock_responses/orders.json
new file mode 100644
index 0000000..3a92972
--- /dev/null
+++ b/tests/mock_responses/orders.json
@@ -0,0 +1,215 @@
+{
+ "status": "success",
+ "data": [
+ {
+ "account_id": "",
+ "placed_by": "DA0017",
+ "order_id": "171228000850038",
+ "exchange_order_id": "211736200053802",
+ "parent_order_id": "",
+ "status": "COMPLETE",
+ "status_message": "",
+ "order_timestamp": "2017-12-28 11:39:14",
+ "exchange_update_timestamp": "",
+ "exchange_timestamp": "2017-12-28 11:39:14",
+ "meta": "",
+ "rejected_by": "",
+ "variety": "regular",
+ "exchange": "MCX",
+ "tradingsymbol": "GOLDGUINEA17DECFUT",
+ "instrument_token": 53505799,
+ "order_type": "LIMIT",
+ "transaction_type": "SELL",
+ "validity": "DAY",
+ "product": "NRML",
+ "quantity": 3,
+ "disclosed_quantity": 0,
+ "price": 23337,
+ "trigger_price": 0,
+ "average_price": 23337,
+ "filled_quantity": 3,
+ "pending_quantity": 0,
+ "cancelled_quantity": 0
+ },
+ {
+ "account_id": "",
+ "placed_by": "DA0017",
+ "order_id": "171228000912853",
+ "exchange_order_id": "1300000002730006",
+ "parent_order_id": "",
+ "status": "COMPLETE",
+ "status_message": "",
+ "order_timestamp": "2017-12-28 12:09:31",
+ "exchange_update_timestamp": "",
+ "exchange_timestamp": "2017-12-28 12:00:28",
+ "meta": "",
+ "rejected_by": "",
+ "variety": "co",
+ "exchange": "NSE",
+ "tradingsymbol": "SBIN",
+ "instrument_token": 779521,
+ "order_type": "LIMIT",
+ "transaction_type": "BUY",
+ "validity": "DAY",
+ "product": "CO",
+ "quantity": 1,
+ "disclosed_quantity": 0,
+ "price": 311,
+ "trigger_price": 0,
+ "average_price": 311,
+ "filled_quantity": 1,
+ "pending_quantity": 0,
+ "cancelled_quantity": 0
+ },
+ {
+ "account_id": "",
+ "placed_by": "DA0017",
+ "order_id": "171228001116651",
+ "exchange_order_id": "211736200111089",
+ "parent_order_id": "",
+ "status": "COMPLETE",
+ "status_message": "",
+ "order_timestamp": "2017-12-28 13:08:49",
+ "exchange_update_timestamp": "",
+ "exchange_timestamp": "2017-12-28 13:08:49",
+ "meta": "",
+ "rejected_by": "",
+ "variety": "regular",
+ "exchange": "MCX",
+ "tradingsymbol": "GOLDGUINEA17DECFUT",
+ "instrument_token": 53505799,
+ "order_type": "LIMIT",
+ "transaction_type": "BUY",
+ "validity": "DAY",
+ "product": "NRML",
+ "quantity": 1,
+ "disclosed_quantity": 0,
+ "price": 23388,
+ "trigger_price": 0,
+ "average_price": 23388,
+ "filled_quantity": 1,
+ "pending_quantity": 0,
+ "cancelled_quantity": 0
+ },
+ {
+ "account_id": "",
+ "placed_by": "DA0017",
+ "order_id": "171228000912854",
+ "exchange_order_id": "1300000002730007",
+ "parent_order_id": "171228000912853",
+ "status": "COMPLETE",
+ "status_message": "",
+ "order_timestamp": "2017-12-28 15:00:40",
+ "exchange_update_timestamp": "",
+ "exchange_timestamp": "2017-12-28 15:00:40",
+ "meta": "",
+ "rejected_by": "",
+ "variety": "co",
+ "exchange": "NSE",
+ "tradingsymbol": "SBIN",
+ "instrument_token": 779521,
+ "order_type": "LIMIT",
+ "transaction_type": "SELL",
+ "validity": "DAY",
+ "product": "CO",
+ "quantity": 1,
+ "disclosed_quantity": 0,
+ "price": 0,
+ "trigger_price": 309,
+ "average_price": 309,
+ "filled_quantity": 1,
+ "pending_quantity": 0,
+ "cancelled_quantity": 0
+ },
+ {
+ "account_id": "",
+ "placed_by": "DA0017",
+ "order_id": "171228001686586",
+ "exchange_order_id": "211736200181323",
+ "parent_order_id": "",
+ "status": "COMPLETE",
+ "status_message": "",
+ "order_timestamp": "2017-12-28 15:28:56",
+ "exchange_update_timestamp": "",
+ "exchange_timestamp": "2017-12-28 15:28:56",
+ "meta": "",
+ "rejected_by": "",
+ "variety": "regular",
+ "exchange": "MCX",
+ "tradingsymbol": "GOLDGUINEA17DECFUT",
+ "instrument_token": 53505799,
+ "order_type": "LIMIT",
+ "transaction_type": "SELL",
+ "validity": "DAY",
+ "product": "NRML",
+ "quantity": 1,
+ "disclosed_quantity": 0,
+ "price": 23349,
+ "trigger_price": 0,
+ "average_price": 23349,
+ "filled_quantity": 1,
+ "pending_quantity": 0,
+ "cancelled_quantity": 0
+ },
+ {
+ "account_id": "",
+ "placed_by": "DA0017",
+ "order_id": "171228001730092",
+ "exchange_order_id": "211736200297236",
+ "parent_order_id": "",
+ "status": "COMPLETE",
+ "status_message": "",
+ "order_timestamp": "2017-12-28 19:28:27",
+ "exchange_update_timestamp": "",
+ "exchange_timestamp": "2017-12-28 19:28:27",
+ "meta": "",
+ "rejected_by": "",
+ "variety": "regular",
+ "exchange": "MCX",
+ "tradingsymbol": "LEADMINI17DECFUT",
+ "instrument_token": 53496327,
+ "order_type": "LIMIT",
+ "transaction_type": "BUY",
+ "validity": "DAY",
+ "product": "NRML",
+ "quantity": 1,
+ "disclosed_quantity": 0,
+ "price": 161.05,
+ "trigger_price": 0,
+ "average_price": 161.05,
+ "filled_quantity": 1,
+ "pending_quantity": 0,
+ "cancelled_quantity": 0
+ },
+ {
+ "account_id": "",
+ "placed_by": "DA0017",
+ "order_id": "171228001731490",
+ "exchange_order_id": "211736200302177",
+ "parent_order_id": "",
+ "status": "COMPLETE",
+ "status_message": "",
+ "order_timestamp": "2017-12-28 19:37:12",
+ "exchange_update_timestamp": "",
+ "exchange_timestamp": "2017-12-28 19:37:12",
+ "meta": "",
+ "rejected_by": "",
+ "variety": "regular",
+ "exchange": "MCX",
+ "tradingsymbol": "LEADMINI17DECFUT",
+ "instrument_token": 53496327,
+ "order_type": "LIMIT",
+ "transaction_type": "SELL",
+ "validity": "DAY",
+ "product": "NRML",
+ "quantity": 1,
+ "disclosed_quantity": 0,
+ "price": 161.2,
+ "trigger_price": 0,
+ "average_price": 161.2,
+ "filled_quantity": 1,
+ "pending_quantity": 0,
+ "cancelled_quantity": 0
+ }
+ ]
+}
diff --git a/tests/mock_responses/positions.json b/tests/mock_responses/positions.json
new file mode 100644
index 0000000..190e42a
--- /dev/null
+++ b/tests/mock_responses/positions.json
@@ -0,0 +1,195 @@
+{
+ "status": "success",
+ "data": {
+ "net": [
+ {
+ "tradingsymbol": "LEADMINI17DECFUT",
+ "exchange": "MCX",
+ "instrument_token": 53496327,
+ "product": "NRML",
+ "quantity": 1,
+ "overnight_quantity": 0,
+ "multiplier": 1000,
+ "average_price": 161.05,
+ "close_price": 0,
+ "last_price": 161.05,
+ "value": -161050,
+ "pnl": 0,
+ "m2m": 0,
+ "unrealised": 0,
+ "realised": 0,
+ "buy_quantity": 1,
+ "buy_price": 161.05,
+ "buy_value": 161050,
+ "buy_m2m": 161050,
+ "sell_quantity": 0,
+ "sell_price": 0,
+ "sell_value": 0,
+ "sell_m2m": 0,
+ "day_buy_quantity": 1,
+ "day_buy_price": 161.05,
+ "day_buy_value": 161050,
+ "day_sell_quantity": 0,
+ "day_sell_price": 0,
+ "day_sell_value": 0
+ },
+ {
+ "tradingsymbol": "GOLDGUINEA17DECFUT",
+ "exchange": "MCX",
+ "instrument_token": 53505799,
+ "product": "NRML",
+ "quantity": 0,
+ "overnight_quantity": 3,
+ "multiplier": 1,
+ "average_price": 0,
+ "close_price": 23232,
+ "last_price": 23355,
+ "value": 801,
+ "pnl": 801,
+ "m2m": 276,
+ "unrealised": 801,
+ "realised": 0,
+ "buy_quantity": 4,
+ "buy_price": 23139.75,
+ "buy_value": 92559,
+ "buy_m2m": 93084,
+ "sell_quantity": 4,
+ "sell_price": 23340,
+ "sell_value": 93360,
+ "sell_m2m": 93360,
+ "day_buy_quantity": 1,
+ "day_buy_price": 23388,
+ "day_buy_value": 23388,
+ "day_sell_quantity": 4,
+ "day_sell_price": 23340,
+ "day_sell_value": 93360
+ },
+ {
+ "tradingsymbol": "SBIN",
+ "exchange": "NSE",
+ "instrument_token": 779521,
+ "product": "CO",
+ "quantity": 0,
+ "overnight_quantity": 0,
+ "multiplier": 1,
+ "average_price": 0,
+ "close_price": 0,
+ "last_price": 308.4,
+ "value": -2,
+ "pnl": -2,
+ "m2m": -2,
+ "unrealised": -2,
+ "realised": 0,
+ "buy_quantity": 1,
+ "buy_price": 311,
+ "buy_value": 311,
+ "buy_m2m": 311,
+ "sell_quantity": 1,
+ "sell_price": 309,
+ "sell_value": 309,
+ "sell_m2m": 309,
+ "day_buy_quantity": 1,
+ "day_buy_price": 311,
+ "day_buy_value": 311,
+ "day_sell_quantity": 1,
+ "day_sell_price": 309,
+ "day_sell_value": 309
+ }
+ ],
+ "day": [
+ {
+ "tradingsymbol": "GOLDGUINEA17DECFUT",
+ "exchange": "MCX",
+ "instrument_token": 53505799,
+ "product": "NRML",
+ "quantity": -3,
+ "overnight_quantity": 0,
+ "multiplier": 1,
+ "average_price": 23340,
+ "close_price": 23232,
+ "last_price": 23355,
+ "value": 69972,
+ "pnl": -93,
+ "m2m": -93,
+ "unrealised": -93,
+ "realised": 0,
+ "buy_quantity": 1,
+ "buy_price": 23388,
+ "buy_value": 23388,
+ "buy_m2m": 23388,
+ "sell_quantity": 4,
+ "sell_price": 23340,
+ "sell_value": 93360,
+ "sell_m2m": 93360,
+ "day_buy_quantity": 1,
+ "day_buy_price": 23388,
+ "day_buy_value": 23388,
+ "day_sell_quantity": 4,
+ "day_sell_price": 23340,
+ "day_sell_value": 93360
+ },
+ {
+ "tradingsymbol": "LEADMINI17DECFUT",
+ "exchange": "MCX",
+ "instrument_token": 53496327,
+ "product": "NRML",
+ "quantity": 1,
+ "overnight_quantity": 0,
+ "multiplier": 1000,
+ "average_price": 161.05,
+ "close_price": 0,
+ "last_price": 161.05,
+ "value": -161050,
+ "pnl": 0,
+ "m2m": 0,
+ "unrealised": 0,
+ "realised": 0,
+ "buy_quantity": 1,
+ "buy_price": 161.05,
+ "buy_value": 161050,
+ "buy_m2m": 161050,
+ "sell_quantity": 0,
+ "sell_price": 0,
+ "sell_value": 0,
+ "sell_m2m": 0,
+ "day_buy_quantity": 1,
+ "day_buy_price": 161.05,
+ "day_buy_value": 161050,
+ "day_sell_quantity": 0,
+ "day_sell_price": 0,
+ "day_sell_value": 0
+ },
+ {
+ "tradingsymbol": "SBIN",
+ "exchange": "NSE",
+ "instrument_token": 779521,
+ "product": "CO",
+ "quantity": 0,
+ "overnight_quantity": 0,
+ "multiplier": 1,
+ "average_price": 0,
+ "close_price": 0,
+ "last_price": 308.4,
+ "value": -2,
+ "pnl": -2,
+ "m2m": -2,
+ "unrealised": -2,
+ "realised": 0,
+ "buy_quantity": 1,
+ "buy_price": 311,
+ "buy_value": 311,
+ "buy_m2m": 311,
+ "sell_quantity": 1,
+ "sell_price": 309,
+ "sell_value": 309,
+ "sell_m2m": 309,
+ "day_buy_quantity": 1,
+ "day_buy_price": 311,
+ "day_buy_value": 311,
+ "day_sell_quantity": 1,
+ "day_sell_price": 309,
+ "day_sell_value": 309
+ }
+ ]
+ }
+}
diff --git a/tests/mock_responses/profile.json b/tests/mock_responses/profile.json
new file mode 100644
index 0000000..e4eca98
--- /dev/null
+++ b/tests/mock_responses/profile.json
@@ -0,0 +1,35 @@
+{
+ "status": "success",
+ "data": {
+ "user_id": "AB1234",
+ "user_type": "investor",
+ "email": "xxxyyy@gmail.com",
+ "user_name": "AxAx Bxx",
+ "user_shortname": "abc",
+ "broker": "ZERODHA",
+ "exchanges": [
+ "BSE",
+ "BFO",
+ "NFO",
+ "MCX",
+ "CDS",
+ "NSE"
+ ],
+ "products": [
+ "BO",
+ "CNC",
+ "CO",
+ "MIS",
+ "NRML"
+ ],
+ "order_types": [
+ "LIMIT",
+ "MARKET",
+ "SL",
+ "SL-M"
+ ],
+ "meta": {
+ "demat_consent": "XXXX"
+ }
+ }
+}
diff --git a/tests/mock_responses/quote.json b/tests/mock_responses/quote.json
new file mode 100644
index 0000000..75e8076
--- /dev/null
+++ b/tests/mock_responses/quote.json
@@ -0,0 +1,159 @@
+{
+ "status": "success",
+ "data": {
+ "NSE:INFY": {
+ "instrument_token": 408065,
+ "timestamp": "2018-01-12 10:40:29",
+ "last_price": 1074.8,
+ "last_quantity": 55,
+ "last_trade_time": "2018-01-12 10:40:28",
+ "average_price": 1077.03,
+ "volume": 1368065,
+ "buy_quantity": 240020,
+ "sell_quantity": 509481,
+ "ohlc": {
+ "open": 1085.8,
+ "high": 1085.9,
+ "low": 1070.9,
+ "close": 1075.8
+ },
+ "net_change": 0,
+ "oi": 0,
+ "oi_day_high": 0,
+ "oi_day_low": 0,
+ "depth": {
+ "buy": [
+ {
+ "price": 1074.8,
+ "quantity": 35,
+ "orders": 1
+ },
+ {
+ "price": 1074.65,
+ "quantity": 5,
+ "orders": 1
+ },
+ {
+ "price": 1074.6,
+ "quantity": 14,
+ "orders": 1
+ },
+ {
+ "price": 1074.5,
+ "quantity": 1529,
+ "orders": 3
+ },
+ {
+ "price": 1074.45,
+ "quantity": 139,
+ "orders": 1
+ }
+ ],
+ "sell": [
+ {
+ "price": 1074.85,
+ "quantity": 32,
+ "orders": 1
+ },
+ {
+ "price": 1075,
+ "quantity": 1264,
+ "orders": 18
+ },
+ {
+ "price": 1075.1,
+ "quantity": 14,
+ "orders": 1
+ },
+ {
+ "price": 1075.2,
+ "quantity": 600,
+ "orders": 1
+ },
+ {
+ "price": 1075.25,
+ "quantity": 22,
+ "orders": 2
+ }
+ ]
+ }
+ },
+ "NSE:SBIN": {
+ "instrument_token": 408065,
+ "timestamp": "2018-01-12 10:40:29",
+ "last_price": 1074.8,
+ "last_quantity": 55,
+ "last_trade_time": "2018-01-12 10:40:28",
+ "average_price": 1077.03,
+ "volume": 1368065,
+ "buy_quantity": 240020,
+ "sell_quantity": 509481,
+ "ohlc": {
+ "open": 1085.8,
+ "high": 1085.9,
+ "low": 1070.9,
+ "close": 1075.8
+ },
+ "net_change": 0,
+ "oi": 0,
+ "oi_day_high": 0,
+ "oi_day_low": 0,
+ "depth": {
+ "buy": [
+ {
+ "price": 1074.8,
+ "quantity": 35,
+ "orders": 1
+ },
+ {
+ "price": 1074.65,
+ "quantity": 5,
+ "orders": 1
+ },
+ {
+ "price": 1074.6,
+ "quantity": 14,
+ "orders": 1
+ },
+ {
+ "price": 1074.5,
+ "quantity": 1529,
+ "orders": 3
+ },
+ {
+ "price": 1074.45,
+ "quantity": 139,
+ "orders": 1
+ }
+ ],
+ "sell": [
+ {
+ "price": 1074.85,
+ "quantity": 32,
+ "orders": 1
+ },
+ {
+ "price": 1075,
+ "quantity": 1264,
+ "orders": 18
+ },
+ {
+ "price": 1075.1,
+ "quantity": 14,
+ "orders": 1
+ },
+ {
+ "price": 1075.2,
+ "quantity": 600,
+ "orders": 1
+ },
+ {
+ "price": 1075.25,
+ "quantity": 22,
+ "orders": 2
+ }
+ ]
+ }
+ }
+ }
+}
diff --git a/tests/mock_responses/trades.json b/tests/mock_responses/trades.json
new file mode 100644
index 0000000..c5a0950
--- /dev/null
+++ b/tests/mock_responses/trades.json
@@ -0,0 +1,19 @@
+{
+ "status": "success",
+ "data": [
+ {
+ "average_price": 310.7,
+ "exchange": "NSE",
+ "exchange_order_id": "1300000001887410",
+ "exchange_timestamp": "2017-12-29 12:02:05",
+ "instrument_token": 779521,
+ "order_id": "171229000724687",
+ "order_timestamp": "12:02:05",
+ "product": "CNC",
+ "quantity": 1,
+ "trade_id": "75894751",
+ "tradingsymbol": "SBIN",
+ "transaction_type": "BUY"
+ }
+ ]
+ }
diff --git a/tests/mock_responses/trigger_range.json b/tests/mock_responses/trigger_range.json
new file mode 100644
index 0000000..f84ba5c
--- /dev/null
+++ b/tests/mock_responses/trigger_range.json
@@ -0,0 +1,15 @@
+{
+ "status": "success",
+ "data": {
+ "NSE:INFY": {
+ "instrument_token": 0,
+ "lower": 1075.599,
+ "upper": 1138.2
+ },
+ "NSE:RELIANCE": {
+ "instrument_token": 0,
+ "lower": 870.57475,
+ "upper": 902.15
+ }
+ }
+}