o
    gj                     @   sF   d Z ddlZddlZddlZddlmZ ddlmZ G dd dZ	dS )z
This file contains functions to create a client class that accesses the Schwab api
Coded by Tyler Bowers
Github: https://github.com/tylerebowers/Schwab-API-Python
    N   )Stream)Tokensc                %   @   sJ  e Zd ZdkddZdefd	d
ZdlddZdeeB dB fddZ	dZ
	 dejfddZdmdedejfddZdmdededejfddZdndedejeB dejeB dededejfd d!Zded"edejfd#d$Zded%eeB dejfd&d'Zded%eeB dejfd(d)Zded%eeB d"edejfd*d+ZdndejeB dejeB dededejf
d,d-Z	 dmded.ejeB d/ejeB d0ed1edejfd2d3Zded4eeB dejfd5d6Zdejfd7d8Z	 dod9ee eB ded:edejfd;d<Zdmd=ededejfd>d?Z			dpd1ed@edAedBedCedDedEedFedGejeB dHejeB dIedJedKedLedMedNedOedejf$dPdQZd1edejfdRdSZ 		dqd1edTedUedVedWed.ejeB d/edXedYedejfdZd[Z!dnd1ed\edWedejfd]d^Z"dmd9ee d_ejeB dejfd`daZ#dmdbed_ejeB dejfdcddZ$d1edeedejfdfdgZ%dheeB dejfdidjZ&dS )rClienthttps://127.0.0.1tokens.json   FTc                 C   sX   |dkrt dd| _|| _|| _t| |||||d| _t| | _| jr*td dS dS )ah  
        Initialize a client to access the Schwab API.
        :param app_key: app key credentials
        :type app_key: str
        :param app_secret: app secret credentials
        :type app_secret: str
        :param callback_url: url for callback
        :type callback_url: str
        :param tokens_file: path to tokens file
        :type tokens_file: str
        :param timeout: request timeout
        :type timeout: int
        :param verbose: print extra information
        :type verbose: bool
        :param update_tokens_auto: update tokens automatically
        :type update_tokens_auto: bool
        r   zJTimeout must be greater than 0 and is recommended to be 5 seconds or more.z2.3.0)update_tokens_autoz*[Schwabdev] Client Initialization CompleteN)		Exceptionversiontimeoutverboser   tokensr   streamprint)selfapp_key
app_secretcallback_urltokens_filer   r   r	    r   //var/www/html/StreammingVPS/schwabdev/client.py__init__   s   
zClient.__init__paramsc                 C   s(   t | D ]}|| du r||= q|S )z
        Removes None (null) values
        :param params: params to remove None values from
        :type params: dict
        :return: params without None values
        :rtype: dict
        N)listkeys)r   r   keyr   r   r   _params_parser0   s   zClient._params_parserN8601c                 C   s   |du s	t |tr|S |dkr| dd dd  dS |dkr)t| S |dkr5t| d	 S |d
kr>|dS |S )ad  
        Convert time to the correct format, passthrough if a string, preserve None if None for params parser
        :param dt: datetime.pyi object to convert
        :type dt: datetime.pyi | str | None
        :param form: what to convert input to
        :type form: str
        :return: converted time or passthrough
        :rtype: str | None
        Nr   +r   Zepochepoch_msi  
YYYY-MM-DDz%Y-%m-%d)
isinstancestr	isoformatsplitint	timestampstrftime)r   dtformr   r   r   _time_convert<   s   
 
zClient._time_convertlc                 C   s&   |du rdS t |tu rd|S |S )z
        Convert python list to string or passthough if already a string i.e ["a", "b"] -> "a,b"
        :param l: list to convert
        :type l: list | str | None
        :return: converted string or passthrough
        :rtype: str | None
        N,)typer   join)r   r/   r   r   r   _format_listS   s
   
zClient._format_listzhttps://api.schwabapi.comreturnc                 C   (   t j| j ddd| jj i| jdS )a  
        Account numbers in plain text cannot be used outside of headers or request/response bodies. As the first step consumers must invoke this service to retrieve the list of plain text/encrypted value pairs, and use encrypted account values for all subsequent calls for any accountNumber request.
        :return: All linked account numbers and hashes
        :rtype: request.Response
        z"/trader/v1/accounts/accountNumbersAuthorizationBearer headersr   requestsget_base_api_urlr   access_tokenr   r   r   r   r   account_linkedh      zClient.account_linkedfieldsc                 C   4   t j| j ddd| jj i| d|i| jdS )a  
        All the linked account information for the user logged in. The balances on these accounts are displayed by default however the positions on these accounts will be displayed based on the "positions" flag.
        :param fields: fields to return (options: "positions")
        :type fields: str | None
        :return: details for all linked accounts
        :rtype: request.Response
        /trader/v1/accounts/r6   r7   rB   r9   r   r   r;   r<   r=   r   r>   r   r   )r   rB   r   r   r   account_details_allr   
   zClient.account_details_allaccountHashc                 C   s8   t j| j d| dd| jj i| d|i| jdS )a  
        Specific account information with balances and positions. The balance information on these accounts is displayed by default but Positions will be returned based on the "positions" flag.
        :param accountHash: account hash from account_linked()
        :type accountHash: str
        :param fields: fields to return
        :type fields: str | None
        :return: details for one linked account
        :rtype: request.Response
        rD   r6   r7   rB   rE   rF   )r   rI   rB   r   r   r   account_details   s
   
zClient.account_detailsfromEnteredTimetoEnteredTime
maxResultsstatusc                 C   sR   t j| j d| ddd| jj d| || |d| |d|d| jdS )	a  
        All orders for a specific account. Orders retrieved can be filtered based on input parameters below. Maximum date range is 1 year.
        :param accountHash: account hash from account_linked()
        :type accountHash: str
        :param fromEnteredTime: from entered time
        :type fromEnteredTime: datetime.pyi | str
        :param toEnteredTime: to entered time
        :type toEnteredTime: datetime.pyi | str
        :param maxResults: maximum number of results
        :type maxResults: int| None
        :param status: status ("AWAITING_PARENT_ORDER"|"AWAITING_CONDITION"|"AWAITING_STOP_CONDITION"|"AWAITING_MANUAL_REVIEW"|"ACCEPTED"|"AWAITING_UR_OUT"|"PENDING_ACTIVATION"|"QUEUED"|"WORKING"|"REJECTED"|"PENDING_CANCEL"|"CANCELED"|"PENDING_REPLACE"|"REPLACED"|"FILLED"|"EXPIRED"|"NEW"|"AWAITING_RELEASE_TIME"|"PENDING_ACKNOWLEDGEMENT"|"PENDING_RECALL"|"UNKNOWN")
        :type status: str| None
        :return: orders for one linked account hash
        :rtype: request.Response
        rD   /ordersapplication/jsonr7   Acceptr6   r   rM   rK   rL   rN   rE   r;   r<   r=   r   r>   r   r.   r   )r   rI   rK   rL   rM   rN   r   r   r   account_orders   s   zClient.account_ordersorderc                 C   s4   t j| j d| ddd| jj dd|| jdS )ay  
        Place an order for a specific account.
        :param accountHash: account hash from account_linked()
        :type accountHash: str
        :param order: order dictionary, examples in Schwab docs
        :type order: dict
        :return: order number in response header (if immediately filled then order number not returned)
        :rtype: request.Response
        rD   rO   rP   r7   rR   r6   zContent-Typer9   jsonr   )r;   postr=   r   r>   r   )r   rI   rV   r   r   r   order_place   s   
zClient.order_placeorderIdc                 C   2   t j| j d| d| dd| jj i| jdS )a(  
        Get a specific order by its ID, for a specific account
        :param accountHash: account hash from account_linked()
        :type accountHash: str
        :param orderId: order id
        :type orderId: int | str
        :return: order details
        :rtype: request.Response
        rD   /orders/r6   r7   r8   r:   r   rI   r\   r   r   r   order_details      
zClient.order_detailsc                 C   r]   )a)  
        Cancel a specific order by its ID, for a specific account
        :param accountHash: account hash from account_linked()
        :type accountHash: str
        :param orderId: order id
        :type orderId: str|int
        :return: response code
        :rtype: request.Response
        rD   r^   r6   r7   r8   )r;   deleter=   r   r>   r   r_   r   r   r   order_cancel   ra   zClient.order_cancelc                 C   s8   t j| j d| d| dd| jj dd|| jdS )a  
        Replace an existing order for an account. The existing order will be replaced by the new order. Once replaced, the old order will be canceled and a new order will be created.
        :param accountHash: account hash from account_linked()
        :type accountHash: str
        :param orderId: order id
        :type orderId: str|int
        :param order: order dictionary, examples in Schwab docs
        :type order: dict
        :return: response code
        :rtype: request.Response
        rD   r^   rP   r7   rW   rX   )r;   putr=   r   r>   r   )r   rI   r\   rV   r   r   r   order_replace   s   zClient.order_replacec                 C   sL   t j| j ddd| jj d| || |d| |d|d| jdS )a+  
        Get all orders for all accounts
        :param fromEnteredTime: start date
        :type fromEnteredTime: datetime.pyi | str
        :param toEnteredTime: end date
        :type toEnteredTime: datetime.pyi | str
        :param maxResults: maximum number of results (set to None for default 3000)
        :type maxResults: int | None
        :param status: status ("AWAITING_PARENT_ORDER"|"AWAITING_CONDITION"|"AWAITING_STOP_CONDITION"|"AWAITING_MANUAL_REVIEW"|"ACCEPTED"|"AWAITING_UR_OUT"|"PENDING_ACTIVATION"|"QUEUED"|"WORKING"|"REJECTED"|"PENDING_CANCEL"|"CANCELED"|"PENDING_REPLACE"|"REPLACED"|"FILLED"|"EXPIRED"|"NEW"|"AWAITING_RELEASE_TIME"|"PENDING_ACKNOWLEDGEMENT"|"PENDING_RECALL"|"UNKNOWN")
        :type status: str | None
        :return: all orders
        :rtype: request.Response
        z/trader/v1/ordersrP   r7   rQ   r   rS   rE   rT   )r   rK   rL   rM   rN   r   r   r   account_orders_all   s   zClient.account_orders_all	startDateendDatetypessymbolc                 C   sR   t j| j d| ddd| jj i| || |d| |d||d| jdS )a  
        All transactions for a specific account. Maximum number of transactions in response is 3000. Maximum date range is 1 year.
        :param accountHash: account hash number
        :type accountHash: str
        :param startDate: start date
        :type startDate: datetime.pyi | str
        :param endDate: end date
        :type endDate: datetime.pyi | str
        :param types: transaction type ("TRADE, RECEIVE_AND_DELIVER, DIVIDEND_OR_INTEREST, ACH_RECEIPT, ACH_DISBURSEMENT, CASH_RECEIPT, CASH_DISBURSEMENT, ELECTRONIC_FUND, WIRE_OUT, WIRE_IN, JOURNAL, MEMORANDUM, MARGIN_CALL, MONEY_MARKET, SMA_ADJUSTMENT")
        :type types: str
        :param symbol: symbol
        :return: list of transactions for a specific account
        :rtype: request.Response
        rD   z/transactionsr6   r7   r   )accountNumberrg   rh   rj   ri   rE   rT   )r   rI   rg   rh   ri   rj   r   r   r   transactions   s   zClient.transactionstransactionIdc                 C   s:   t j| j d| d| dd| jj i||d| jdS )aX  
        Get specific transaction information for a specific account
        :param accountHash: account hash number
        :type accountHash: str
        :param transactionId: transaction id
        :type transactionId: str|int
        :return: transaction details of transaction id using accountHash
        :rtype: request.Response
        rD   z/transactions/r6   r7   )rk   rm   rE   r:   )r   rI   rm   r   r   r   transaction_details  s
   
zClient.transaction_detailsc                 C   r5   )z
        Get user preference information for the logged in user.
        :return: User Preferences and Streaming Info
        :rtype: request.Response
        z/trader/v1/userPreferencer6   r7   r8   r:   r?   r   r   r   preferences%  rA   zClient.preferencessymbols
indicativec              	   C   s>   t j| j ddd| jj i| | |||d| jdS )a  
        Get quotes for a list of tickers
        :param symbols: list of symbols strings (e.g. "AMD,INTC" or ["AMD", "INTC"])
        :type symbols: [str] | str
        :param fields: string of fields to get ("all", "quote", "fundamental")
        :type fields: str | None
        :param indicative: whether to get indicative quotes (True/False)
        :type indicative: boolean | None
        :return: list of quotes
        :rtype: request.Response
        z/marketdata/v1/quotesr6   r7   )rp   rB   rq   rE   )r;   r<   r=   r   r>   r   r3   r   )r   rp   rB   rq   r   r   r   quotes3  s   zClient.quotes	symbol_idc                 C   sB   t j| j dtj| ddd| jj i| d|i| j	dS )aP  
        Get quote for a single symbol
        :param symbol_id: ticker symbol
        :type symbol_id: str (e.g. "AAPL", "/ES", "USD/EUR")
        :param fields: string of fields to get ("all", "quote", "fundamental")
        :type fields: str | None
        :return: quote for a single symbol
        :rtype: request.Response
        z/marketdata/v1/z/quotesr6   r7   rB   rE   )
r;   r<   r=   urllibparse
quote_plusr   r>   r   r   )r   rs   rB   r   r   r   quoteE  s
   
zClient.quotecontractTypestrikeCountincludeUnderlyingQuotestrategyintervalstrikerangefromDatetoDate
volatilityunderlyingPriceinterestRatedaysToExpirationexpMonth
optionTypeentitlementc                 C   s   t j| j ddd| jj i| i d|d|d|d|d|d	|d
|d|d| |	dd| |
dd|d|d|d|d|d|d|| jdS )a  
        Get Option Chain including information on options contracts associated with each expiration for a ticker.
        :param symbol: ticker symbol
        :type symbol: str
        :param contractType: contract type ("CALL"|"PUT"|"ALL")
        :type contractType: str
        :param strikeCount: strike count
        :type strikeCount: int
        :param includeUnderlyingQuote: include underlying quote (True|False)
        :type includeUnderlyingQuote: boolean
        :param strategy: strategy ("SINGLE"|"ANALYTICAL"|"COVERED"|"VERTICAL"|"CALENDAR"|"STRANGLE"|"STRADDLE"|"BUTTERFLY"|"CONDOR"|"DIAGONAL"|"COLLAR"|"ROLL)
        :type strategy: str
        :param interval: Strike interval
        :type interval: str
        :param strike: Strike price
        :type strike: float
        :param range: range ("ITM"|"NTM"|"OTM"...)
        :type range: str
        :param fromDate: from date
        :type fromDate: datetime.pyi | str
        :param toDate: to date
        :type toDate: datetime.pyi | str
        :param volatility: volatility
        :type volatility: float
        :param underlyingPrice: underlying price
        :type underlyingPrice: float
        :param interestRate: interest rate
        :type interestRate: float
        :param daysToExpiration: days to expiration
        :type daysToExpiration: int
        :param expMonth: expiration month ("JAN"|"FEB"|"MAR"|"APR"|"MAY"|"JUN"|"JUL"|"AUG"|"SEP"|"OCT"|"NOV"|"DEC"|"ALL")
        :type expMonth: str
        :param optionType: option type ("CALL"|"PUT")
        :type optionType: str
        :param entitlement: entitlement ("PN"|"NP"|"PP")
        :type entitlement: str
        :return: list of option chains
        :rtype: request.Response
        z/marketdata/v1/chainsr6   r7   rj   rx   ry   rz   r{   r|   r}   r~   r   r$   r   r   r   r   r   r   r   r   rE   rT   )r   rj   rx   ry   rz   r{   r|   r}   r~   r   r   r   r   r   r   r   r   r   r   r   r   option_chainsT  sF   *zClient.option_chainsc                 C   rC   )z
        Get an option expiration chain for a ticker
        :param symbol: ticker symbol
        :type symbol: str
        :return: option expiration chain
        :rtype: request.Response
        z/marketdata/v1/expirationchainr6   r7   rj   rE   rF   )r   rj   r   r   r   option_expiration_chain  rH   zClient.option_expiration_chain
periodTypeperiodfrequencyType	frequencyneedExtendedHoursDataneedPreviousClosec
           
      C   sT   t j| j ddd| jj i| |||||| |d| |d||	d	| jdS )a  
        Get price history for a ticker
        :param symbol: ticker symbol
        :type symbol: str
        :param periodType: period type ("day"|"month"|"year"|"ytd")
        :type periodType: str
        :param period: period
        :type period: int
        :param frequencyType: frequency type ("minute"|"daily"|"weekly"|"monthly")
        :type frequencyType: str
        :param frequency: frequency (1|5|10|15|30)
        :type frequency: int
        :param startDate: start date
        :type startDate: datetime.pyi | str
        :param endDate: end date
        :type endDate: datetime.pyi | str
        :param needExtendedHoursData: need extended hours data (True|False)
        :type needExtendedHoursData: boolean
        :param needPreviousClose: need previous close (True|False)
        :type needPreviousClose: boolean
        :return: dictionary of containing candle history
        :rtype: request.Response
        z/marketdata/v1/pricehistoryr6   r7   r#   )	rj   r   r   r   r   rg   rh   r   r   rE   rT   )
r   rj   r   r   r   r   rg   rh   r   r   r   r   r   price_history  s   


zClient.price_historysortc                 C   s<   t j| j d| dd| jj d| ||d| jdS )a  
        Get movers in a specific index and direction
        :param symbol: symbol ("$DJI"|"$COMPX"|"$SPX"|"NYSE"|"NASDAQ"|"OTCBB"|"INDEX_ALL"|"EQUITY_ALL"|"OPTION_ALL"|"OPTION_PUT"|"OPTION_CALL")
        :type symbol: str
        :param sort: sort ("VOLUME"|"TRADES"|"PERCENT_CHANGE_UP"|"PERCENT_CHANGE_DOWN")
        :type sort: str
        :param frequency: frequency (0|1|5|10|30|60)
        :type frequency: int
        :return: movers
        :rtype: request.Response
        z/marketdata/v1/movers/rP   r7   )acceptr6   )r   r   rE   rF   )r   rj   r   r   r   r   r   movers  s
   zClient.moversdatec              
   C   s>   t j| j ddd| jj i| || |dd| jdS )aO  
        Get Market Hours for dates in the future across different markets.
        :param symbols: list of market symbols ("equity", "option", "bond", "future", "forex")
        :type symbols: list
        :param date: date
        :type date: datetime.pyi | str
        :return: market hours
        :rtype: request.Response
        z/marketdata/v1/marketsr6   r7   r$   )marketsr   rE   rT   )r   rp   r   r   r   r   market_hours  s   

zClient.market_hours	market_idc              
   C   s@   t j| j d| dd| jj i| d| |di| jdS )a<  
        Get Market Hours for dates in the future for a single market.
        :param market_id: market id ("equity"|"option"|"bond"|"future"|"forex")
        :type market_id: str
        :param date: date
        :type date: datetime.pyi | str
        :return: market hours
        :rtype: request.Response
        z/marketdata/v1/markets/r6   r7   r   r$   rE   rT   )r   r   r   r   r   r   market_hour  s
   
zClient.market_hour
projectionc                 C   s0   t j| j ddd| jj i||d| jdS )aD  
        Get instruments for a list of symbols
        :param symbol: symbol
        :type symbol: str
        :param projection: projection ("symbol-search"|"symbol-regex"|"desc-search"|"desc-regex"|"search"|"fundamental")
        :type projection: str
        :return: instruments
        :rtype: request.Response
        z/marketdata/v1/instrumentsr6   r7   )rj   r   rE   r:   )r   rj   r   r   r   r   instruments  s
   
zClient.instrumentscusip_idc                 C   s,   t j| j d| dd| jj i| jdS )z
        Get instrument for a single cusip
        :param cusip_id: cusip id
        :type cusip_id: str|int
        :return: instrument
        :rtype: request.Response
        z/marketdata/v1/instruments/r6   r7   r8   r:   )r   r   r   r   r   instrument_cusip  s   zClient.instrument_cusip)r   r   r   FT)Nr   )N)NN)NF)NNNNNNNNNNNNNNNN)NNNNNNNN)'__name__
__module____qualname__r   dictr   r.   r   r&   r3   r=   r;   Responser@   rG   rJ   datetimer)   rU   r[   r`   rc   re   rf   rl   rn   ro   boolrr   rw   anyr   r   r   r   r   r   r   r   r   r   r   r   r      s    
 

2 .2
&
5"
#$ r   )
__doc__r   r;   urllib.parsert   r   r   r   r   r   r   r   r   r   <module>   s    