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; $nlast_price = floatval($o->last_price); - $o->strike = floatval($o->strike); - $o->tick_size = floatval($o->tick_size); - $o->lot_size = floatval($o->lot_size); - - if (!empty($o->expiry) && strlen($o->expiry) == 10) { - $o->expiry = new DateTime($o->expiry, new DateTimeZone("Asia/Kolkata")); - } - - $records[] = $o; - } - } - - return $records; - } - - - /** - * Parse a CSV dump into an array of objects. - * @param string $csv Complete CSV dump. - * @return array - */ - private function _parseMFInstrumentsCSV($csv) { - $lines = explode("\n", $csv); - - $records = []; - $head = []; - for($n=0; $nminimum_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; - } - - /** - * Parse HTTP response headers to a list. - * @param string $headers Header string from an HTTP request. - * @return array - */ - private function _parseHeaders($headers) { - $head = ["status_code" => 200]; - - foreach($headers as $k=>$v) { - $h = explode(":", $v, 2); - - if(isset($h[1])) { - $head[strtolower(trim($h[0]))] = trim( $h[1] ); - } else { - $head[] = $v; - if(preg_match("/HTTP\/[0-9\.]+\s+([0-9]+)/is", $v, $out)) { - $head["status_code"] = intval($out[1]); - } - } - } - - return $head; - } -} - -/** - * Base exeception for client exceptions. - */ -class KiteException extends Exception { - public function __construct($message, $code = 0, Exception $previous = null) { - parent::__construct($message, $code, $previous); - } - - public function __toString() { - return get_class($this) . " ({$this->code}) '{$this->message}'\n"; - } -} - -/** - * An unclassified, general error. Default code is 500. - */ -class GeneralException extends KiteException { - public function __construct($message, $code = 500, Exception $previous = null) { - parent::__construct($message, $code, $previous); - } -} - -/** - * Represents all token and authentication related errors. Default code is 403. - */ -class TokenException extends KiteException { - public function __construct($message, $code = 403, Exception $previous = null) { - parent::__construct($message, $code, $previous); - } -} - -/** - * An unclassified, general 500 error. - */ -class PermissionException extends KiteException { - public function __construct($message, $code = 403, Exception $previous = null) { - parent::__construct($message, $code, $previous); - } -} - -/** - * Represents all order placement and manipulation errors. - */ -class OrderException extends KiteException { - public function __construct($message, $code = 500, Exception $previous = null) { - parent::__construct($message, $code, $previous); - } -} - -/** - * Represents user input errors such as missing and invalid parameters. - */ -class InputException extends KiteException { - public function __construct($message, $code = 500, Exception $previous = null) { - parent::__construct($message, $code, $previous); - } -} - -/** - * Represents a bad response from the backend Order Management System (OMS). - */ -class DataException extends KiteException { - public function __construct($message, $code = 502, Exception $previous = null) { - parent::__construct($message, $code, $previous); - } -} - -/** - * Represents a network issue between Kite and the backend Order Management System (OMS). - */ -class NetworkException extends KiteException { - public function __construct($message, $code = 503, Exception $previous = null) { - parent::__construct($message, $code, $previous); - } -} diff --git a/phpunit.xml.dist b/phpunit.xml.dist new file mode 100644 index 0000000..6aee655 --- /dev/null +++ b/phpunit.xml.dist @@ -0,0 +1,31 @@ + + + + + tests + + + + + ./src + + + + + + + + + + + diff --git a/psalm.xml.dist b/psalm.xml.dist new file mode 100644 index 0000000..ba70fff --- /dev/null +++ b/psalm.xml.dist @@ -0,0 +1,17 @@ + + + + + + + + + + diff --git a/src/Exception/DataException.php b/src/Exception/DataException.php new file mode 100644 index 0000000..20d09af --- /dev/null +++ b/src/Exception/DataException.php @@ -0,0 +1,22 @@ +code}) '{$this->message}'\n"; + } +} diff --git a/src/Exception/NetworkException.php b/src/Exception/NetworkException.php new file mode 100644 index 0000000..5f773c9 --- /dev/null +++ b/src/Exception/NetworkException.php @@ -0,0 +1,22 @@ + "/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 + /** @var int */ + private $timeout; + + /** @var mixed */ + private $apiKey; + + /** @var mixed */ + private $accessToken; + + /** @var mixed */ + private $debug; + + /** @var Closure */ + private $sessionHook; + + /** + * Initialise a new Kite Connect client instance. + * + * @param string $apiKey The Kite Connect API key issued to you. + * @param string|null $accessToken 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|null $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 bool $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( + string $apiKey, + string $accessToken = null, + string $root = null, + bool $debug = false, + int $timeout = 7, + \GuzzleHttp\Client $guzzleClient = null + ) { + $this->apiKey = $apiKey; + $this->accessToken = $accessToken; + $this->debug = $debug; + $this->sessionHook = null; + $this->timeout = $timeout; + $this->guzzleClient = $guzzleClient; + + if ($root) { + $this->baseUrl = $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 Closure $method The callback function that should be called in case of a TokenError error. + * @return void + */ + public function setSessionExpiryHook(Closure $method): void + { + $this->sessionHook = $method; + } + + /** + * Set the `access_token` received after a successful authentication. + * + * @param string $accessToken The `access_token` received after a successful authentication token exchange. + * @return void + */ + public function setAccessToken(string $accessToken): void + { + $this->accessToken = $accessToken; + } + + /** + * Get the remote login url to which a user should be redirected to initiate the login flow. + * + * @return string + */ + public function getLoginURL(): string + { + return "{$this->loginUrl}?api_key={$this->apiKey}&v=3"; + } + + /** + * Do the token exchange with the `request_token` obtained after the login flow, + * and retrieve the `access_token` required for all subsequent requests. The + * response contains not just the `access_token`, but metadata for + * the user who has authenticated. + * + * @param string $requestToken Token obtained from the GET params after a successful login redirect + * @param string $apiSecret The API secret issued with the API key. + * @return mixed + * @throws Exception + */ + public function generateSession(string $requestToken, string $apiSecret) + { + $checksum = hash("sha256", $this->apiKey . $requestToken . $apiSecret); + + $response = $this->post("api.token", [ + "api_key" => $this->apiKey, + "request_token" => $requestToken, + "checksum" => $checksum, + ]); + + if ($response->access_token) { + $this->setAccessToken($response->access_token); + } + + if ($response->login_time) { + $response->login_time = new DateTime($response->login_time, new DateTimeZone("Asia/Kolkata")); + } + + return $response; + } + + /** + * Kill the session by invalidating the access token. + * + * @param string|null $accessToken (Optional) `access_token` to invalidate. Default is the active `access_token`. + * @return mixed + * @throws DataException + * @throws GeneralException + * @throws InputException + * @throws NetworkException + * @throws OrderException + * @throws PermissionException + * @throws TokenException + */ + public function invalidateAccessToken($accessToken = null) + { + if (! $accessToken) { + $accessToken = $this->accessToken; + } + + return $this->delete("api.token.invalidate", [ + "access_token" => $accessToken, + "api_key" => $this->apiKey, + ]); + } + + /** + * Renew access token by active refresh token. + * Renewed access token is implicitly set. + * + * @param string $refreshToken Token obtained from previous successful login. + * @param string $apiSecret The API secret issued with the API key. + * @return array + * @throws DataException + * @throws GeneralException + * @throws InputException + * @throws NetworkException + * @throws OrderException + * @throws PermissionException + * @throws TokenException + */ + public function renewAccessToken(string $refreshToken, string $apiSecret): array + { + $checksum = hash("sha256", $this->apiKey . $refreshToken . $apiSecret); + + $resp = $this->post("api.token.renew", [ + "api_key" => $this->apiKey, + "refresh_token" => $refreshToken, + "checksum" => $checksum, + ]); + + if (! empty($resp->access_token)) { + $this->setAccessToken($resp->access_token); + } + + return $resp; + } + + /** + * Invalidate refresh token. + * + * @param string $refreshToken Refresh token to invalidate. + * @return mixed + * @throws DataException + * @throws GeneralException + * @throws InputException + * @throws NetworkException + * @throws OrderException + * @throws PermissionException + * @throws TokenException + */ + public function invalidateRefreshToken(string $refreshToken): Mixed_ + { + return $this->delete("api.token.invalidate", [ + "refresh_token" => $refreshToken, + "api_key" => $this->apiKey, + ]); + } + + /** + * Get user profile. + * + * @return mixed + * @throws DataException + * @throws GeneralException + * @throws InputException + * @throws NetworkException + * @throws OrderException + * @throws PermissionException + * @throws TokenException + */ + public function getProfile(): mixed + { + 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 mixed + * @throws DataException + * @throws GeneralException + * @throws InputException + * @throws NetworkException + * @throws OrderException + * @throws PermissionException + * @throws TokenException + */ + public function getMargins(?string $segment = null): mixed + { + 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 mixed|null + * @throws DataException + * @throws GeneralException + * @throws InputException + * @throws NetworkException + * @throws OrderException + * @throws PermissionException + * @throws TokenException + */ + public function placeOrder(string $variety, array $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 $orderId "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 mixed + * @throws DataException + * @throws GeneralException + * @throws InputException + * @throws NetworkException + * @throws OrderException + * @throws PermissionException + * @throws TokenException + */ + public function modifyOrder(string $variety, string $orderId, array $params): Mixed_ + { + $params["variety"] = $variety; + $params["order_id"] = $orderId; + + return $this->put("order.modify", $params); + } + + /** + * Cancel an open order. + * + * @param string $variety "variety" Order variety (ex. bo, co, amo, regular). + * @param string $orderId "order_id" Order id. + * @param array|null $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 mixed + * @throws DataException + * @throws GeneralException + * @throws InputException + * @throws NetworkException + * @throws OrderException + * @throws PermissionException + * @throws TokenException + */ + public function cancelOrder(string $variety, string $orderId, array $params = null) + { + if (! $params) { + $params = []; + } + + $params["variety"] = $variety; + $params["order_id"] = $orderId; + + return $this->delete("order.cancel", $params); + } + + /** + * Exit a BO or CO. + * + * @param string $variety "variety" Order variety (ex. bo, co, amo, regular). + * @param string $orderId "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 mixed + * @throws DataException + * @throws GeneralException + * @throws InputException + * @throws NetworkException + * @throws OrderException + * @throws PermissionException + * @throws TokenException + */ + public function exitOrder(string $variety, string $orderId, array $params) + { + return $this->cancelOrder($variety, $orderId, $params); + } + + /** + * Get the list of all orders placed for the day. + * + * @return array + * @throws DataException + * @throws Exception + */ + public function getOrders(): array + { + return $this->formatResponseArray($this->get("orders")); + } + + /** + * Get history of the individual order. + * @param string $orderId 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 + * @throws DataException + * @throws Exception + */ + public function getOrderHistory(string $orderId): array + { + return $this->formatResponseArray($this->get("order.info", ["order_id" => $orderId])); + } + + /** + * 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 + * @throws DataException + * @throws GeneralException + * @throws InputException + * @throws NetworkException + * @throws OrderException + * @throws PermissionException + * @throws TokenException + */ + public function orderMargins(array $params): array + { + return $this->post("order.margins", (array)json_encode($params), 'application/json'); + } + + /** + * Retrieve the list of trades executed. + * @return array + * @throws DataException + * @throws Exception + */ + public function getTrades(): array + { + return $this->formatResponseArray($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 $orderId 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 + * @throws DataException + * @throws Exception + */ + public function getOrderTrades(string $orderId): array + { + return $this->formatResponseArray($this->get("order.trades", ["order_id" => $orderId])); + } + + /** + * Retrieve the list of positions + * + * @return mixed + * @throws DataException + * @throws GeneralException + * @throws InputException + * @throws NetworkException + * @throws OrderException + * @throws PermissionException + * @throws TokenException + */ + public function getPositions(): mixed + { + return $this->get("portfolio.positions"); + } + + /** + * Retrieve the list of holdings + * + * @return array + * @throws DataException + * @throws GeneralException + * @throws InputException + * @throws NetworkException + * @throws OrderException + * @throws PermissionException + * @throws TokenException + */ + public function getHoldings(): array + { + 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 + * @throws DataException + * @throws GeneralException + * @throws InputException + * @throws NetworkException + * @throws OrderException + * @throws PermissionException + * @throws TokenException + */ + public function convertPosition(array $params): bool + { + 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 + * @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 + } + } +}