""" AUTHOR: Khushal P Soonderji DATE: Tuesday, 7th jan., 2024. OBJECTIVE: To provide a structure to represent trading tick updates from Zerodha. REFERENCES: N/A DOWNLOADS: N/A """ # ***************************************************************************************************************** # ***** **** # *** IMPORT *** # ***** **** # ***************************************************************************************************************** # To make sibling directories accessible for imports: import sys sys.path.append(".") sys.path.append("..") # For making data behaviour_models: from pydantic import BaseModel, Field, field_validator, PastDatetime, model_validator, AwareDatetime, computed_field from typing import Optional, Literal, Union, List # My utils: from utils_v2.string import json from utils_v2.string import regex from utils_v2.date_time import date_time # To work with date and time: import datetime # ***************************************************************************************************************** # ***** **** # *** MACROS / ONE-TIME INIT *** # ***** **** # ***************************************************************************************************************** # --- Nothing Yet # ***************************************************************************************************************** # ***** **** # *** VARIABLES *** # ***** **** # ***************************************************************************************************************** # --- Nothing Yet # ***************************************************************************************************************** # ***** **** # *** FUNCTIONS *** # ***** **** # ***************************************************************************************************************** class OneZerodhaKiteMarketDepth(BaseModel): price: float = Field( description = "a price at which trader(s) are willing to trade this instrument", frozen = True, alias = "price" ) qty: int = Field( description = "the no. of shares available at the above price", frozen = True, alias = "quantity" ) orders: int = Field( description = "how many orders have contributed to the above quantity", frozen = True, alias = "orders" ) @computed_field def lqdty(self) -> float: return self.price * self.qty # ┏┓ ┏• # ┃ ┏┓┏┓╋┓┏┓ # ┗┛┗┛┛┗┛┗┗┫ # ┛ class Config: extra = "forbid" # --------------------------------------------------------------------------------------------------------------------- class ZerodhaKiteMarketDepth(BaseModel): buy: List[OneZerodhaKiteMarketDepth] = Field( description = "the buying side market depth", frozen = True ) sell: List[OneZerodhaKiteMarketDepth] = Field( description = "the selling side market depth", frozen = True ) # ┏┓ ┏• # ┃ ┏┓┏┓╋┓┏┓ # ┗┛┗┛┛┗┛┗┗┫ # ┛ class Config: extra = "forbid" # ┓┏ ┓• ┓ • # ┃┃┏┓┃┓┏┫┏┓╋┓┏┓┏┓ # ┗┛┗┻┗┗┗┻┗┻┗┗┗┛┛┗ @field_validator("buy", mode = "after") def sort_buying_depth(cls, value): value.sort(key = lambda x: x.price, reverse = True) return value @field_validator("sell", mode = "after") def sort_selling_depth(cls, value): value.sort(key = lambda x: x.price, reverse = False) return value # --------------------------------------------------------------------------------------------------------------------- class ZerodhaKiteTick(BaseModel): tickMode: Literal["ltp", "quote", "full"] = Field( description = "The mode in which this tick was received.", frozen = True ) instrumentToken: int = Field( description = "The code by which Zerodha identifies this instrument.", frozen = True ) tradeable: bool = Field( description = "Whether, or not, this instrument is tradeable.", frozen = True ) exchange: str = Field( description = "The exchange on which this instrument gets traded.", frozen = True ) prevClose: float | None = Field( description = "The previous session's closing price for this instrument.", frozen = True, default = None, validate_default = True ) ltp: float = Field( description = "The last price of this instrument.", frozen = True ) qty: int | None = Field( description = "How many units were traded in this tick.", frozen = True, default = None, validate_default = True ) chg: float | None = Field( description = "The absolute change since the previous close.", frozen = True, default = None, validate_default = True ) pChg: float | None = Field( description = "The percentage change since the previous close.", frozen = True, default = None, validate_default = True ) o: float | None = Field( description = "This session's open price.", frozen = True, default = None, validate_default = True ) h: float | None = Field( description = "This session's highest price.", frozen = True, default = None, validate_default = True ) l: float | None = Field( description = "This session's lowest price.", frozen = True, default = None, validate_default = True ) c: float | None = Field( description = "This session's close price; typically the same as the LTP.", frozen = True, default = None, validate_default = True ) totVol: int | None = Field( description = "The total volume of this instrument that has been traded in this session.", frozen = True, default = None, validate_default = True ) vwap: float | None = Field( description = "The volume weighted average price in this session.", frozen = True, default = None, validate_default = True ) totBuyQty: int | None = Field( description = "The total open buy qty. on the exchange for this symbol.", frozen = True, default = None, validate_default = True ) totSellQty: int | None = Field( description = "The total open sell qty. on the exchange for this symbol.", frozen = True, default = None, validate_default = True ) oi: int | None = Field( description = "The total open interest of this instrument (if derivative).", frozen = True, default = None, validate_default = True ) oiDayHigh: int | None = Field( description = "This session's highest open interest of this instrument (if derivative).", frozen = True, default = None, validate_default = True ) oiDayLow: int | None = Field( description = "This session's lowest open interest of this instrument (if derivative).", frozen = True, default = None, validate_default = True ) tradeTs: AwareDatetime | None = Field( description = "The last trade time (UTC) of this instrument.", frozen = True, default = None, validate_default = True ) tradeTz: str | None = Field( description = "The timezone (pytz compatible) in which the last trade time should be interpreted.", frozen = True, default = None, validate_default = True, examples = ["UTC", "Asia/Kolkata"] ) exchgTs: AwareDatetime | None = Field( description = "The time (UTC) at which this update was received from the exchange.", frozen = True, default = None, validate_default = True ) exchgTz: str | None = Field( description = "The timezone (pytz compatible) in which the exchange's time should be interpreted.", frozen = True, default = None, validate_default = True, examples = ["UTC", "Asia/Kolkata"] ) depth: ZerodhaKiteMarketDepth | None = Field( description = "The market depth data for this instrument at the time of this tick.", frozen = True, default = None, validate_default = True ) # ┏┓ ┏┓ ┓ ┏┓• ┓ ┓ # ┣┫┓┏╋┏┓━━┃ ┏┓┏┳┓┏┓┓┏╋┏┓┏┫ ┣ ┓┏┓┃┏┫┏ # ┛┗┗┻┗┗┛ ┗┛┗┛┛┗┗┣┛┗┻┗┗ ┗┻ ┻ ┗┗ ┗┗┻┛ # ┛ pass # ┏┓ ┏• # ┃ ┏┓┏┓╋┓┏┓ # ┗┛┗┛┛┗┛┗┗┫ # ┛ class Config: extra = "forbid" # ┏┓ ┏┓ # ┃ ┓┏┏╋┏┓┏┳┓ ┣ ┓┏┏┓┏┏ # ┗┛┗┻┛┗┗┛┛┗┗ ┻ ┗┻┛┗┗┛ pass # ┓┏ ┓• ┓ • # ┃┃┏┓┃┓┏┫┏┓╋┓┏┓┏┓ # ┗┛┗┻┗┗┗┻┗┻┗┗┗┛┛┗ pass # ***************************************************************************************************************** # ***** **** # *** MAIN PROGRAM *** # ***** **** # ***************************************************************************************************************** if __name__ == "__main__": pass