def get_quote(ticker, jsonify=None): """ Gets quote information for a single stock. :param ticker: The ticker of the stock. :type ticker: str :param jsonify: If set to false, will return the raw response object. \ If set to True, will return a dictionary parsed using the JSON format. :type jsonify: Optional[str] :returns: Returns a tuple where the first entry in the tuple is a requests reponse object \ or a dictionary parsed using the JSON format and the second entry is an error string or \ None if there was not an error. """ url = URLS.quote(ticker) data, error = request_get(url, None, jsonify) return data, error
def get_instrument(cusip, jsonify=None): """ Gets instrument data for a specific stock. :param cusip: The CUSIP for a stock. :type cusip: str :param jsonify: If set to false, will return the raw response object. \ If set to True, will return a dictionary parsed using the JSON format. :type jsonify: Optional[str] :returns: Returns a tuple where the first entry in the tuple is a requests reponse object \ or a dictionary parsed using the JSON format and the second entry is an error string or \ None if there was not an error. """ url = URLS.instrument(cusip) data, error = request_get(url, None, jsonify) return data, error
def get_quotes(tickers, jsonify=None): """ Gets quote information for multiple stocks. The stock string should be comma separated with no spaces. :param ticker: The string list of stock tickers. :type ticker: str :param jsonify: If set to false, will return the raw response object. \ If set to True, will return a dictionary parsed using the JSON format. :type jsonify: Optional[str] :returns: Returns a tuple where the first entry in the tuple is a requests reponse object \ or a dictionary parsed using the JSON format and the second entry is an error string or \ None if there was not an error. """ url = URLS.quotes() payload = {"symbol": tickers} data, error = request_get(url, payload, jsonify) return data, error
def get_transaction(account_id, transaction_id, jsonify=None): """ Get account information for a specific account. :param account_id: The account id. :type account_id: str :param transaction_id: The transaction id. :type transaction_id: str :param jsonify: If set to false, will return the raw response object. \ If set to True, will return a dictionary parsed using the JSON format. :type jsonify: Optional[str] :returns: Returns a tuple where the first entry in the tuple is a requests reponse object \ or a dictionary parsed using the JSON format and the second entry is an error string or \ None if there was not an error. """ url = URLS.transaction(account_id, transaction_id) data, error = request_get(url, None, jsonify) return data, error
def place_order(account_id, order_payload, jsonify=None): """ Place an order for a given account. :param account_id: The account id. :type account_id: str :param order_payload: A dictionary of key value pairs for the infromation you want to send to order. :type order_payload: str :param jsonify: If set to false, will return the raw response object. \ If set to True, will return a dictionary parsed using the JSON format. :type jsonify: Optional[str] :returns: Returns a tuple where the first entry in the tuple is a requests reponse object \ or a dictionary parsed using the JSON format and the second entry is an error string or \ None if there was not an error. """ url = URLS.orders(account_id) data, error = request_headers(url, order_payload, jsonify) return data, error
def cancel_order(account_id, order_id, jsonify=None): """ Cancel an order for a given account. :param account_id: The account id. :type account_id: str :param order_id: The order id. :type order_id: str :param jsonify: If set to false, will return the raw response object. \ If set to True, will return a dictionary parsed using the JSON format. :type jsonify: Optional[str] :returns: Returns a tuple where the first entry in the tuple is a requests reponse object \ or a dictionary parsed using the JSON format and the second entry is an error string or \ None if there was not an error. """ url = URLS.order(account_id, order_id) data, error = request_delete(url, jsonify) return data, error
def get_orders_for_account(account_id, max_results=None, from_time=None, to_time=None, status=None, jsonify=None): """ Gets all the orders for a given account. :param account_id: The account id. :type account_id: Optional[str] :param max_results: The max number of orders to retrieve. :type max_results: Optional[str] :param from_time: Specifies that no orders entered before this time should be returned. Valid ISO-8601 formats are : \ yyyy-MM-dd. Date must be within 60 days from today's date. 'toEnteredTime' must also be set. :type from_time: Optional[str] :param to_time: Specifies that no orders entered after this time should be returned.Valid ISO-8601 formats are : \ yyyy-MM-dd. 'fromEnteredTime' must also be set. :type to_time: Optional[str] :param status: Specifies that only orders of this status should be returned. Possible values are \ AWAITING_PARENT_ORDER, AWAITING_CONDITION, AWAITING_MANUAL_REVIEW, ACCEPTED, AWAITING_UR_OUT, PENDING_ACTIVATION, QUEUED \ WORKING, REJECTED, PENDING_CANCEL, CANCELED, PENDING_REPLACE, REPLACED, FILLED, EXPIRED :type status: Optional[str] :param jsonify: If set to false, will return the raw response object. \ If set to True, will return a dictionary parsed using the JSON format. :type jsonify: Optional[str] :returns: Returns a tuple where the first entry in the tuple is a requests reponse object \ or a dictionary parsed using the JSON format and the second entry is an error string or \ None if there was not an error. """ url = URLS.orders(account_id) payload = {} if max_results: payload["maxResults"] = max_results if from_time: payload["fromEnteredTime"] = from_time if to_time: payload["toEnteredTime"] = to_time if status: payload["status"] = status data, error = request_get(url, payload, jsonify) return data, error
def get_accounts(options=None, jsonify=None): """ Gets all accounts associated with your API keys. :param options: Balances displayed by default, additional fields can be added here by adding positions or orders\ As a comma separated list. Example:"positions,orders" :type options: str :param jsonify: If set to false, will return the raw response object. \ If set to True, will return a dictionary parsed using the JSON format. :type jsonify: Optional[str] :returns: Returns a tuple where the first entry in the tuple is a requests reponse object \ or a dictionary parsed using the JSON format and the second entry is an error string or \ None if there was not an error. """ url = URLS.accounts() if options: payload = {"fields": options} else: payload = None data, error = request_get(url, payload, jsonify) return data, error
def get_hours_for_markets(markets, date, jsonify=None): """ Gets market hours for various markets. :param markets: The markets for which you're requesting market hours, comma-separated. \ Valid markets are EQUITY, OPTION, FUTURE, BOND, or FOREX. :type markets: str :param date: The date for which market hours information is requested. Valid ISO-8601 formats are : \ yyyy-MM-dd and yyyy-MM-dd'T'HH:mm:ssz. :type date: str :param jsonify: If set to false, will return the raw response object. \ If set to True, will return a dictionary parsed using the JSON format. :type jsonify: Optional[str] :returns: Returns a tuple where the first entry in the tuple is a requests reponse object \ or a dictionary parsed using the JSON format and the second entry is an error string or \ None if there was not an error. """ url = URLS.markets() payload = {"markets": markets, "date": date} data, error = request_get(url, payload, jsonify) return data, error
def get_transactions(id, type_value=None, symbol=None, start_date=None, end_date=None, jsonify=None): """ Get account information for a specific account. :param id: The account id. :type id: str :param type_value: Only transactions with the specified type will be returned. ALL, TRADE, \ BUY_ONLY, SELL_ONLY, CASH_IN_OR_CASH_OUT, CHECKING, DIVIDEND, INTEREST, OTHER, ADVISOR_FEES :type type_value: Optional[str] param symbol: Only transactions with the specified symbol will be returned. :type symbol: Optional[str] param start_date: Only transactions after the Start Date will be returned. \ Note: The maximum date range is one year. Valid ISO-8601 formats are :yyyy-MM-dd. :type start_date: Optional[str] param end_date: Only transactions before the End Date will be returned. \ Note: The maximum date range is one year. Valid ISO-8601 formats are :yyyy-MM-dd. :type end_date: Optional[str] :param jsonify: If set to false, will return the raw response object. \ If set to True, will return a dictionary parsed using the JSON format. :type jsonify: Optional[str] :returns: Returns a tuple where the first entry in the tuple is a requests reponse object \ or a dictionary parsed using the JSON format and the second entry is an error string or \ None if there was not an error. """ url = URLS.transactions(id) payload = {} if type_value: payload["type"] = type_value if symbol: payload["symbol"] = symbol if start_date: payload["startDate"] = start_date if end_date: payload["endDate"] = end_date data, error = request_get(url, payload, jsonify) return data, error
def get_movers(market, direction, change, jsonify=None): """ Gets market hours for a specific market. :param market: The market for which you're requesting market hours, comma-separated. \ Valid markets are $DJI, $COMPX, or $SPX.X. :type market: str :param direction: To return movers with the specified directions of "up" or "down". :type direction: str :param change: To return movers with the specified change types of "percent" or "value". :type change: str :param jsonify: If set to false, will return the raw response object. \ If set to True, will return a dictionary parsed using the JSON format. :type jsonify: Optional[str] :returns: Returns a tuple where the first entry in the tuple is a requests reponse object \ or a dictionary parsed using the JSON format and the second entry is an error string or \ None if there was not an error. """ url = URLS.movers(market) payload = {"direction": direction, "change": change} data, error = request_get(url, payload, jsonify) return data, error
def search_instruments(ticker_string, projection, jsonify=None): """ Gets a list of all the instruments data for tickers that match a search string. :param ticker_string: Value to pass to the search. See projection description for more information. :type ticker_string: str :param projection: The type of request:\n * symbol-search: Retrieve instrument data of a specific symbol or cusip * symbol-regex: Retrieve instrument data for all symbols matching regex. Example: symbol=XYZ.* will return all symbols beginning with XYZ * desc-search: Retrieve instrument data for instruments whose description contains the word supplied. Example: symbol=FakeCompany will return all instruments with FakeCompany in the description. * desc-regex: Search description with full regex support. Example: symbol=XYZ.[A-C] returns all instruments whose descriptions contain a word beginning with XYZ followed by a character A through C. * fundamental: Returns fundamental data for a single instrument specified by exact symbol. :type projection: str :param jsonify: If set to false, will return the raw response object. \ If set to True, will return a dictionary parsed using the JSON format. :type jsonify: Optional[str] :returns: Returns a tuple where the first entry in the tuple is a requests reponse object \ or a dictionary parsed using the JSON format and the second entry is an error string or \ None if there was not an error. """ url = URLS.instruments() payload = {"symbol": ticker_string, "projection": projection} data, error = request_get(url, payload, jsonify) return data, error
def login(encryption_passcode): """ Set the authorization token so the API can be used. Gets a new authorization token every 30 minutes using the refresh token. Gets a new refresh token every 60 days. :param encryption_passcode: Encryption key created by generate_encryption_passcode(). :type encryption_passcode: str """ if type(encryption_passcode) is str: encryption_passcode = encryption_passcode.encode() cipher_suite = Fernet(encryption_passcode) # Check that file exists before trying to read from it. data_dir = Path.home().joinpath(DATA_DIR_NAME) pickle_path = data_dir.joinpath(PICKLE_NAME) if not pickle_path.exists(): raise FileExistsError( "Please Call login_first_time() to create pickle file.") # Read the information from the pickle file. with pickle_path.open("rb") as pickle_file: pickle_data = pickle.load(pickle_file) access_token = cipher_suite.decrypt( pickle_data['authorization_token']).decode() refresh_token = cipher_suite.decrypt( pickle_data['refresh_token']).decode() client_id = cipher_suite.decrypt(pickle_data['client_id']).decode() authorization_timestamp = pickle_data['authorization_timestamp'] refresh_timestamp = pickle_data['refresh_timestamp'] # Authorization tokens expire after 30 mins. Refresh tokens expire after 90 days, # but you need to request a fresh authorization and refresh token before it expires. authorization_delta = timedelta(seconds=1800) refresh_delta = timedelta(days=60) url = URLS.oauth() # If it has been longer than 60 days. Get a new refresh and authorization token. # Else if it has been longer than 30 minutes, get only a new authorization token. if (datetime.now() - refresh_timestamp > refresh_delta): payload = { "grant_type": "refresh_token", "access_type": "offline", "refresh_token": refresh_token, "client_id": client_id } data, _ = request_data(url, payload, True) if "access_token" not in data and "refresh_token" not in data: raise ValueError( "Refresh token is no longer valid. Call login_first_time() to get a new refresh token." ) access_token = data["access_token"] refresh_token = data["refresh_token"] with pickle_path.open("wb") as pickle_file: pickle.dump( { 'authorization_token': cipher_suite.encrypt(access_token.encode()), 'refresh_token': cipher_suite.encrypt(refresh_token.encode()), 'client_id': cipher_suite.encrypt(client_id.encode()), 'authorization_timestamp': datetime.now(), 'refresh_timestamp': datetime.now() }, pickle_file) elif (datetime.now() - authorization_timestamp > authorization_delta): payload = { "grant_type": "refresh_token", "refresh_token": refresh_token, "client_id": client_id } data, _ = request_data(url, payload, True) if "access_token" not in data: raise ValueError( "Refresh token is no longer valid. Call login_first_time() to get a new refresh token." ) access_token = data["access_token"] # Write new data to file. Do not replace the refresh timestamp. with pickle_path.open("wb") as pickle_file: pickle.dump( { 'authorization_token': cipher_suite.encrypt(access_token.encode()), 'refresh_token': cipher_suite.encrypt(refresh_token.encode()), 'client_id': cipher_suite.encrypt(client_id.encode()), 'authorization_timestamp': datetime.now(), 'refresh_timestamp': refresh_timestamp }, pickle_file) # Store authorization token in session information to be used with API calls. auth_token = "Bearer {0}".format(access_token) update_session("Authorization", auth_token) update_session("apikey", client_id) set_login_state(True) return auth_token
def get_price_history(ticker, period_type, frequency_type, frequency, period=None, start_date=None, end_date=None, needExtendedHoursData=True, jsonify=None): """ Gets the price history of a stock. :param ticker: The stock ticker. :type ticker: str :param period_type: The type of period to show. Valid values are day, month, year, or ytd (year to date). Default is day. :type period_type: str :param frequency_type: The type of frequency with which a new candle is formed. \ Valid frequencyTypes by period_type (defaults marked with an asterisk):\n * day: minute* * month: daily, weekly* * year: daily, weekly, monthly* * ytd: daily, weekly* :type frequency_type: str :param frequency: The number of the frequencyType to be included in each candle. \ Valid frequencies by frequencyType (defaults marked with an asterisk):\n * minute: 1*, 5, 10, 15, 30 * daily: 1* * weekly: 1* * monthly: 1* :type frequency: str :param period: The number of periods to show. Valid periods by periodType (defaults marked with an asterisk):\n * day: 1, 2, 3, 4, 5, 10* * month: 1*, 2, 3, 6 * year: 1*, 2, 3, 5, 10, 15, 20 * ytd: 1* :type period: Optional[str] :param start_date: Start date as milliseconds since epoch. If startDate and endDate are provided, period should not be provided. :type start_date: Optional[str] :param end_date: End date as milliseconds since epoch. If startDate and endDate are provided, period should not be provided. Default is previous trading day. :type end_date: Optional[str] :param needExtendedHoursData: true to return extended hours data, false for regular market hours only. Default is true. :type needExtendedHoursData: Optional[str] :param jsonify: If set to false, will return the raw response object. \ If set to True, will return a dictionary parsed using the JSON format. :type jsonify: Optional[str] :returns: Returns a tuple where the first entry in the tuple is a requests reponse object \ or a dictionary parsed using the JSON format and the second entry is an error string or \ None if there was not an error. """ if (start_date or end_date) and period: raise ValueError( "If start_date and end_date are provided, period should not be provided." ) url = URLS.price_history(ticker) payload = { "periodType": period_type, "frequencyType": frequency_type, "frequency": frequency, "needExtendedHoursData": needExtendedHoursData } if period: payload["period"] = period if start_date: payload["startDate"] = start_date if end_date: payload["endDate"] = end_date data, error = request_get(url, payload, jsonify) return data, error
def get_option_chains(ticker, contract_type="ALL", strike_count="10", include_quotes="FALSE", strategy="SINGLE", interval=None, strike_price=None, range_value="ALL", from_date=None, to_date=None, volatility=None, underlying_price=None, interest_rate=None, days_to_expiration=None, exp_month="ALL", option_type="ALL", jsonify=None): """ Gets instrument data for a specific stock. :param ticker: The stock ticker. :type ticker: str :param contract_type: Type of contracts to return in the chain. Can be CALL, PUT, or ALL. Default is ALL. :type contract_type: Optional[str] :param strike_count: The number of strikes to return above and below the at-the-money price. :type strike_count: Optional[str] :param include_quotes: Include quotes for options in the option chain. Can be TRUE or FALSE. Default is FALSE. :type include_quotes: Optional[str] :param strategy: Passing a value returns a Strategy Chain. Possible values are SINGLE, ANALYTICAL (allows use of the volatility, \ underlyingPrice, interestRate, and daysToExpiration params to calculate theoretical values), COVERED, VERTICAL, CALENDAR, \ STRANGLE, STRADDLE, BUTTERFLY, CONDOR, DIAGONAL, COLLAR, or ROLL. Default is SINGLE. :type strategy: Optional[str] :param interval: Strike interval for spread strategy chains (see strategy param). :type interval: Optional[str] :param strike_price: Provide a strike price to return options only at that strike price. :type strike_price: Optional[str] :param range_value: Returns options for the given range. Default is ALL. Possible values are:\n * ITM: In-the-money * NTM: Near-the-money * OTM: Out-of-the-money * SAK: Strikes Above Market * SBK: Strikes Below Market * SNK: Strikes Near Market * ALL: All Strikes :type range_value: Optional[str] :param from_date: Only return expirations after this date. For strategies, expiration refers to the \ nearest term expiration in the strategy. Valid ISO-8601 formats are: yyyy-MM-dd and yyyy-MM-dd'T'HH:mm:ssz. :type from_date: Optional[str] :param to_date: Only return expirations before this date. For strategies, expiration refers to the \ nearest term expiration in the strategy. Valid ISO-8601 formats are: yyyy-MM-dd and yyyy-MM-dd'T'HH:mm:ssz. :type to_date: Optional[str] :param volatility: Volatility to use in calculations. Applies only to ANALYTICAL strategy chains (see strategy param). :type volatility: Optional[str] :param underlying_price: Underlying price to use in calculations. Applies only to ANALYTICAL strategy chains (see strategy param). :type underlying_price: Optional[str] :param interest_rate: Interest rate to use in calculations. Applies only to ANALYTICAL strategy chains (see strategy param). :type interest_rate: Optional[str] :param days_to_expiration: Days to expiration to use in calculations. Applies only to ANALYTICAL strategy chains (see strategy param). :type days_to_expiration: Optional[str] :param exp_month: Return only options expiring in the specified month. Month is given in the three character format. Example: JAN. Default is ALL. :type exp_month: Optional[str] :param option_type: Type of contracts to return. Default is ALL. Possible values are:\n * S: Standard contracts * NS: Non-standard contracts * ALL: All contracts :type option_type: Optional[str] :param jsonify: If set to false, will return the raw response object. \ If set to True, will return a dictionary parsed using the JSON format. :type jsonify: Optional[str] :returns: Returns a tuple where the first entry in the tuple is a requests reponse object \ or a dictionary parsed using the JSON format and the second entry is an error string or \ None if there was not an error. """ url = URLS.option_chains() payload = { "symbol": ticker, "contractType": contract_type, "strikeCount": strike_count, "includeQuotes": include_quotes, "strategy": strategy, "range": range_value, "expMonth": exp_month, "optionType": option_type } if interval: payload["interval"] = interval if strike_price: payload["strike"] = strike_price if from_date: payload["fromDate"] = from_date if to_date: payload["toDate"] = to_date if volatility: payload["volatility"] = volatility if underlying_price: payload["underlyingPrice"] = underlying_price if interest_rate: payload["interestRate"] = interest_rate if days_to_expiration: payload["daysToExpiration"] = days_to_expiration data, error = request_get(url, payload, jsonify) return data, error