def stream(self, accountID, **kwargs): """ Get a stream of Prices for an Account starting from when the request is made. Args: accountID: Account Identifier instruments: List of Instruments to stream Prices for. snapshot: Flag that enables/disables the sending of a pricing snapshot when initially connecting to the stream. Returns: v20.response.Response containing the results from submitting the request """ request = Request('GET', '/v3/accounts/{accountID}/pricing/stream') request.set_path_param('accountID', accountID) request.set_param('instruments', kwargs.get('instruments')) request.set_param('snapshot', kwargs.get('snapshot')) request.set_stream(True) class Parser(): def __init__(self, ctx): self.ctx = ctx def __call__(self, line): j = json.loads(line.decode('utf-8')) type = j.get("type") if type is None: return ("pricing.Price", self.ctx.pricing.Price.from_dict(j, self.ctx)) elif type == "HEARTBEAT": return ("pricing.PricingHeartbeat", self.ctx.pricing.PricingHeartbeat.from_dict( j, self.ctx)) return ("pricing.Price", self.ctx.pricing.Price.from_dict(j, self.ctx)) request.set_line_parser(Parser(self.ctx)) response = self.ctx.request(request) return response
def list(self, accountID, **kwargs): """List Trades Get a list of Trades for an Account Parameters ---------- accountID : ID of the Account to fetch Trades for. ids : array, optional List of Trade IDs to retrieve. state : , optional The state to filter the requested Trades by. instrument : , optional The instrument to filter the requested Trades by. count : integer, optional The maximum number of Trades to return. beforeID : , optional The maximum Trade ID to return. If not provided the most recent Trades in the Account are returned. """ request = Request('GET', '/v3/accounts/{accountID}/trades') request.set_path_param('accountID', accountID) request.set_param('ids', kwargs.get('ids')) request.set_param('state', kwargs.get('state')) request.set_param('instrument', kwargs.get('instrument')) request.set_param('count', kwargs.get('count')) request.set_param('beforeID', kwargs.get('beforeID')) response = self.ctx.request(request) if response.content_type is None: return response if not response.content_type.startswith("application/json"): return response jbody = json.loads(response.raw_body) parsed_body = {} if response.status is 200: if jbody.get('trades') is not None: parsed_body['trades'] = [ Trade.from_dict(d) for d in jbody.get('trades') ] if jbody.get('lastTransactionID') is not None: parsed_body['lastTransactionID'] = \ jbody.get('lastTransactionID') if response.status is 401: if jbody.get('errorCode') is not None: parsed_body['errorCode'] = \ jbody.get('errorCode') if jbody.get('errorMessage') is not None: parsed_body['errorMessage'] = \ jbody.get('errorMessage') if response.status is 404: if jbody.get('errorCode') is not None: parsed_body['errorCode'] = \ jbody.get('errorCode') if jbody.get('errorMessage') is not None: parsed_body['errorMessage'] = \ jbody.get('errorMessage') if response.status is 405: if jbody.get('errorCode') is not None: parsed_body['errorCode'] = \ jbody.get('errorCode') if jbody.get('errorMessage') is not None: parsed_body['errorMessage'] = \ jbody.get('errorMessage') response.body = parsed_body return response
def position_book(self, instrument, **kwargs): """ Fetch a position book for an instrument. Args: instrument: Name of the Instrument time: The time of the snapshot to fetch. If not specified, then the most recent snapshot is fetched. Returns: v20.response.Response containing the results from submitting the request """ request = Request('GET', '/v3/instruments/{instrument}/positionBook') request.set_path_param('instrument', instrument) request.set_param('time', kwargs.get('time')) response = self.ctx.request(request) if response.content_type is None: return response if not response.content_type.startswith("application/json"): return response jbody = json.loads(response.raw_body) parsed_body = {} # # Parse responses as defined by the API specification # if str(response.status) == "200": if jbody.get('positionBook') is not None: parsed_body['positionBook'] = \ self.ctx.instrument.PositionBook.from_dict( jbody['positionBook'], self.ctx ) elif str(response.status) == "400": if jbody.get('errorCode') is not None: parsed_body['errorCode'] = \ jbody.get('errorCode') if jbody.get('errorMessage') is not None: parsed_body['errorMessage'] = \ jbody.get('errorMessage') elif str(response.status) == "401": if jbody.get('errorCode') is not None: parsed_body['errorCode'] = \ jbody.get('errorCode') if jbody.get('errorMessage') is not None: parsed_body['errorMessage'] = \ jbody.get('errorMessage') elif str(response.status) == "404": if jbody.get('errorCode') is not None: parsed_body['errorCode'] = \ jbody.get('errorCode') if jbody.get('errorMessage') is not None: parsed_body['errorMessage'] = \ jbody.get('errorMessage') elif str(response.status) == "405": if jbody.get('errorCode') is not None: parsed_body['errorCode'] = \ jbody.get('errorCode') if jbody.get('errorMessage') is not None: parsed_body['errorMessage'] = \ jbody.get('errorMessage') # # Unexpected response status # else: parsed_body = jbody response.body = parsed_body return response
def get(self, accountID, **kwargs): """ Get pricing information for a specified list of Instruments within an Account. Args: accountID: Account Identifier instruments: List of Instruments to get pricing for. since: Date/Time filter to apply to the returned prices. Only prices with a time later than this filter will be provided. includeUnitsAvailable: Flag that enables the inclusion of the unitsAvailable field in the returned Price objects. Returns: v20.response.Response containing the results from submitting the request """ request = Request('GET', '/v3/accounts/{accountID}/pricing') request.set_path_param('accountID', accountID) request.set_param('instruments', kwargs.get('instruments')) request.set_param('since', kwargs.get('since')) request.set_param('includeUnitsAvailable', kwargs.get('includeUnitsAvailable')) response = self.ctx.request(request) if response.content_type is None: return response if not response.content_type.startswith("application/json"): return response jbody = json.loads(response.raw_body) parsed_body = {} # # Parse responses as defined by the API specification # if str(response.status) == "200": if jbody.get('prices') is not None: parsed_body['prices'] = [ self.ctx.pricing.Price.from_dict(d, self.ctx) for d in jbody.get('prices') ] elif str(response.status) == "400": if jbody.get('errorCode') is not None: parsed_body['errorCode'] = \ jbody.get('errorCode') if jbody.get('errorMessage') is not None: parsed_body['errorMessage'] = \ jbody.get('errorMessage') elif str(response.status) == "401": if jbody.get('errorCode') is not None: parsed_body['errorCode'] = \ jbody.get('errorCode') if jbody.get('errorMessage') is not None: parsed_body['errorMessage'] = \ jbody.get('errorMessage') elif str(response.status) == "404": if jbody.get('errorCode') is not None: parsed_body['errorCode'] = \ jbody.get('errorCode') if jbody.get('errorMessage') is not None: parsed_body['errorMessage'] = \ jbody.get('errorMessage') elif str(response.status) == "405": if jbody.get('errorCode') is not None: parsed_body['errorCode'] = \ jbody.get('errorCode') if jbody.get('errorMessage') is not None: parsed_body['errorMessage'] = \ jbody.get('errorMessage') # # Unexpected response status # else: parsed_body = jbody response.body = parsed_body return response
def stream( self, accountID, **kwargs ): """Price Stream Get a stream of Prices for an Account starting from when the request is made. Parameters ---------- accountID : ID of the Account to stream Prices for. instruments : array, optional List of Instruments to stream Prices for. snapshot : , optional Flag that enables/disables the sending of a pricing snapshot when initially connecting to the stream. """ request = Request( 'GET', '/v3/accounts/{accountID}/pricing/stream' ) request.set_path_param( 'accountID', accountID ) request.set_param( 'instruments', kwargs.get('instruments') ) request.set_param( 'snapshot', kwargs.get('snapshot') ) request.set_stream(True) class Parser(): def __init__(self, ctx): self.ctx = ctx def __call__(self, line): j = json.loads(line) type = j.get("type") if type is None: return ( "pricing.Price", self.ctx.pricing.Price.from_dict(j) ) elif type == "HEARTBEAT": return ( "pricing.Heartbeat", self.ctx.pricing.Heartbeat.from_dict(j) ) return ( "pricing.Price", self.ctx.pricing.Price.from_dict(j) ) request.set_line_parser( Parser(self.ctx) ) response = self.ctx.request(request) return response
def get( self, accountID, **kwargs ): """ Get pricing information for a specified list of Instruments within an Account. Args: accountID: Account Identifier instruments: List of Instruments to get pricing for. since: Date/Time filter to apply to the response. Only prices and home conversions (if requested) with a time later than this filter (i.e. the price has changed after the since time) will be provided, and are filtered independently. includeUnitsAvailable: Flag that enables the inclusion of the unitsAvailable field in the returned Price objects. includeHomeConversions: Flag that enables the inclusion of the homeConversions field in the returned response. An entry will be returned for each currency in the set of all base and quote currencies present in the requested instruments list. Returns: v20.response.Response containing the results from submitting the request """ request = Request( 'GET', '/v3/accounts/{accountID}/pricing' ) request.set_path_param( 'accountID', accountID ) request.set_param( 'instruments', kwargs.get('instruments') ) request.set_param( 'since', kwargs.get('since') ) request.set_param( 'includeUnitsAvailable', kwargs.get('includeUnitsAvailable') ) request.set_param( 'includeHomeConversions', kwargs.get('includeHomeConversions') ) response = self.ctx.request(request) if response.content_type is None: return response if not response.content_type.startswith("application/json"): return response jbody = json.loads(response.raw_body) parsed_body = {} # # Parse responses as defined by the API specification # if str(response.status) == "200": if jbody.get('prices') is not None: parsed_body['prices'] = [ self.ctx.pricing.ClientPrice.from_dict(d, self.ctx) for d in jbody.get('prices') ] if jbody.get('homeConversions') is not None: parsed_body['homeConversions'] = [ self.ctx.pricing.HomeConversions.from_dict(d, self.ctx) for d in jbody.get('homeConversions') ] if jbody.get('time') is not None: parsed_body['time'] = \ jbody.get('time') elif str(response.status) == "400": if jbody.get('errorCode') is not None: parsed_body['errorCode'] = \ jbody.get('errorCode') if jbody.get('errorMessage') is not None: parsed_body['errorMessage'] = \ jbody.get('errorMessage') elif str(response.status) == "401": if jbody.get('errorCode') is not None: parsed_body['errorCode'] = \ jbody.get('errorCode') if jbody.get('errorMessage') is not None: parsed_body['errorMessage'] = \ jbody.get('errorMessage') elif str(response.status) == "404": if jbody.get('errorCode') is not None: parsed_body['errorCode'] = \ jbody.get('errorCode') if jbody.get('errorMessage') is not None: parsed_body['errorMessage'] = \ jbody.get('errorMessage') elif str(response.status) == "405": if jbody.get('errorCode') is not None: parsed_body['errorCode'] = \ jbody.get('errorCode') if jbody.get('errorMessage') is not None: parsed_body['errorMessage'] = \ jbody.get('errorMessage') # # Unexpected response status # else: parsed_body = jbody response.body = parsed_body return response
def stream(self, accountID, **kwargs): """ Get a stream of Account Prices starting from when the request is made. This pricing stream does not include every single price created for the Account, but instead will provide at most 4 prices per second (every 250 milliseconds) for each instrument being requested. If more than one price is created for an instrument during the 250 millisecond window, only the price in effect at the end of the window is sent. This means that during periods of rapid price movement, subscribers to this stream will not be sent every price. Pricing windows for different connections to the price stream are not all aligned in the same way (i.e. they are not all aligned to the top of the second). This means that during periods of rapid price movement, different subscribers may observe different prices depending on their alignment. Args: accountID: Account Identifier instruments: List of Instruments to stream Prices for. snapshot: Flag that enables/disables the sending of a pricing snapshot when initially connecting to the stream. Returns: v20.response.Response containing the results from submitting the request """ request = Request('GET', '/v3/accounts/{accountID}/pricing/stream') request.set_path_param('accountID', accountID) request.set_param('instruments', kwargs.get('instruments')) request.set_param('snapshot', kwargs.get('snapshot')) request.set_stream(True) class Parser(): def __init__(self, ctx): self.ctx = ctx def __call__(self, line): j = json.loads(line.decode('utf-8')) type = j.get("type") if type is None: return ("pricing.ClientPrice", self.ctx.pricing.ClientPrice.from_dict( j, self.ctx)) elif type == "HEARTBEAT": return ("pricing.PricingHeartbeat", self.ctx.pricing.PricingHeartbeat.from_dict( j, self.ctx)) return ("pricing.ClientPrice", self.ctx.pricing.ClientPrice.from_dict(j, self.ctx)) request.set_line_parser(Parser(self.ctx)) response = self.ctx.request(request) return response
def get_price_range(self, instrument, **kwargs): """ Get pricing information for a specified range of prices. Accounts are not associated in any way with this endpoint. Args: instrument: Name of the Instrument fromTime: The start of the time range to fetch prices for. toTime: The end of the time range to fetch prices for. The current time is used if this parameter is not provided. Returns: v20.response.Response containing the results from submitting the request """ request = Request('GET', '/v3/pricing/range') request.set_path_param('instrument', instrument) request.set_param('from', kwargs.get('fromTime')) request.set_param('to', kwargs.get('toTime')) response = self.ctx.request(request) if response.content_type is None: return response if not response.content_type.startswith("application/json"): return response jbody = json.loads(response.raw_body) parsed_body = {} # # Parse responses as defined by the API specification # if str(response.status) == "200": if jbody.get('prices') is not None: parsed_body['prices'] = [ self.ctx.pricing_common.Price.from_dict(d, self.ctx) for d in jbody.get('prices') ] elif str(response.status) == "400": if jbody.get('errorCode') is not None: parsed_body['errorCode'] = \ jbody.get('errorCode') if jbody.get('errorMessage') is not None: parsed_body['errorMessage'] = \ jbody.get('errorMessage') elif str(response.status) == "401": if jbody.get('errorCode') is not None: parsed_body['errorCode'] = \ jbody.get('errorCode') if jbody.get('errorMessage') is not None: parsed_body['errorMessage'] = \ jbody.get('errorMessage') elif str(response.status) == "404": if jbody.get('errorCode') is not None: parsed_body['errorCode'] = \ jbody.get('errorCode') if jbody.get('errorMessage') is not None: parsed_body['errorMessage'] = \ jbody.get('errorMessage') elif str(response.status) == "405": if jbody.get('errorCode') is not None: parsed_body['errorCode'] = \ jbody.get('errorCode') if jbody.get('errorMessage') is not None: parsed_body['errorMessage'] = \ jbody.get('errorMessage') # # Unexpected response status # else: parsed_body = jbody response.body = parsed_body return response
def candles( self, instrument, **kwargs ): """ Fetch candlestick data for an instrument. Args: instrument: Name of the Instrument price: The Price component(s) to get candlestick data for. Can contain any combination of the characters "M" (midpoint candles) "B" (bid candles) and "A" (ask candles). granularity: The granularity of the candlesticks to fetch count: The number of candlesticks to return in the reponse. Count should not be specified if both the start and end parameters are provided, as the time range combined with the graularity will determine the number of candlesticks to return. fromTime: The start of the time range to fetch candlesticks for. toTime: The end of the time range to fetch candlesticks for. smooth: A flag that controls whether the candlestick is "smoothed" or not. A smoothed candlestick uses the previous candle's close price as its open price, while an unsmoothed candlestick uses the first price from its time range as its open price. includeFirst: A flag that controls whether the candlestick that is covered by the from time should be included in the results. This flag enables clients to use the timestamp of the last completed candlestick received to poll for future candlesticks but avoid receiving the previous candlestick repeatedly. dailyAlignment: The hour of the day (in the specified timezone) to use for granularities that have daily alignments. alignmentTimezone: The timezone to use for the dailyAlignment parameter. Candlesticks with daily alignment will be aligned to the dailyAlignment hour within the alignmentTimezone. Note that the returned times will still be represented in UTC. weeklyAlignment: The day of the week used for granularities that have weekly alignment. Returns: v20.response.Response containing the results from submitting the request """ request = Request( 'GET', '/v3/instruments/{instrument}/candles' ) request.set_path_param( 'instrument', instrument ) request.set_param( 'price', kwargs.get('price') ) request.set_param( 'granularity', kwargs.get('granularity') ) request.set_param( 'count', kwargs.get('count') ) request.set_param( 'from', kwargs.get('fromTime') ) request.set_param( 'to', kwargs.get('toTime') ) request.set_param( 'smooth', kwargs.get('smooth') ) request.set_param( 'includeFirst', kwargs.get('includeFirst') ) request.set_param( 'dailyAlignment', kwargs.get('dailyAlignment') ) request.set_param( 'alignmentTimezone', kwargs.get('alignmentTimezone') ) request.set_param( 'weeklyAlignment', kwargs.get('weeklyAlignment') ) response = self.ctx.request(request) if response.content_type is None: return response if not response.content_type.startswith("application/json"): return response jbody = json.loads(response.raw_body) parsed_body = {} # # Parse responses as defined by the API specification # if str(response.status) == "200": if jbody.get('instrument') is not None: parsed_body['instrument'] = \ jbody.get('instrument') if jbody.get('granularity') is not None: parsed_body['granularity'] = \ jbody.get('granularity') if jbody.get('candles') is not None: parsed_body['candles'] = [ self.ctx.instrument.Candlestick.from_dict(d, self.ctx) for d in jbody.get('candles') ] elif str(response.status) == "400": if jbody.get('errorCode') is not None: parsed_body['errorCode'] = \ jbody.get('errorCode') if jbody.get('errorMessage') is not None: parsed_body['errorMessage'] = \ jbody.get('errorMessage') elif str(response.status) == "401": if jbody.get('errorCode') is not None: parsed_body['errorCode'] = \ jbody.get('errorCode') if jbody.get('errorMessage') is not None: parsed_body['errorMessage'] = \ jbody.get('errorMessage') elif str(response.status) == "404": if jbody.get('errorCode') is not None: parsed_body['errorCode'] = \ jbody.get('errorCode') if jbody.get('errorMessage') is not None: parsed_body['errorMessage'] = \ jbody.get('errorMessage') elif str(response.status) == "405": if jbody.get('errorCode') is not None: parsed_body['errorCode'] = \ jbody.get('errorCode') if jbody.get('errorMessage') is not None: parsed_body['errorMessage'] = \ jbody.get('errorMessage') # # Unexpected response status # else: parsed_body = jbody response.body = parsed_body return response
def list( self, accountID, **kwargs ): """ Get a list of Trades for an Account Args: accountID: Account Identifier ids: List of Trade IDs to retrieve. state: The state to filter the requested Trades by. instrument: The instrument to filter the requested Trades by. count: The maximum number of Trades to return. beforeID: The maximum Trade ID to return. If not provided the most recent Trades in the Account are returned. Returns: v20.response.Response containing the results from submitting the request """ request = Request( 'GET', '/v3/accounts/{accountID}/trades' ) request.set_path_param( 'accountID', accountID ) request.set_param( 'ids', kwargs.get('ids') ) request.set_param( 'state', kwargs.get('state') ) request.set_param( 'instrument', kwargs.get('instrument') ) request.set_param( 'count', kwargs.get('count') ) request.set_param( 'beforeID', kwargs.get('beforeID') ) response = self.ctx.request(request) if response.content_type is None: return response if not response.content_type.startswith("application/json"): return response jbody = json.loads(response.raw_body) parsed_body = {} # # Parse responses as defined by the API specification # if str(response.status) == "200": if jbody.get('trades') is not None: parsed_body['trades'] = [ self.ctx.trade.Trade.from_dict(d, self.ctx) for d in jbody.get('trades') ] if jbody.get('lastTransactionID') is not None: parsed_body['lastTransactionID'] = \ jbody.get('lastTransactionID') elif str(response.status) == "401": if jbody.get('errorCode') is not None: parsed_body['errorCode'] = \ jbody.get('errorCode') if jbody.get('errorMessage') is not None: parsed_body['errorMessage'] = \ jbody.get('errorMessage') elif str(response.status) == "404": if jbody.get('errorCode') is not None: parsed_body['errorCode'] = \ jbody.get('errorCode') if jbody.get('errorMessage') is not None: parsed_body['errorMessage'] = \ jbody.get('errorMessage') elif str(response.status) == "405": if jbody.get('errorCode') is not None: parsed_body['errorCode'] = \ jbody.get('errorCode') if jbody.get('errorMessage') is not None: parsed_body['errorMessage'] = \ jbody.get('errorMessage') # # Unexpected response status # else: parsed_body = jbody response.body = parsed_body return response
def orderBook(self, instrument, **kwargs): print("orderBook() starting...") request = Request('GET', '/v3/instruments/{instrument}/orderBook') request.set_path_param('instrument', instrument) request.set_param('time', kwargs.get('time')) response = self.ctx.request(request) if response.content_type is None: return response if not response.content_type.startswith("application/json"): return response jbody = json.loads(response.raw_body) parsed_body = {} # # Parse responses as defined by the API specification # if str(response.status) == "200": if jbody.get('orderBook') is not None: parsed_body['orderBook'] = \ jbody.get('orderBook') if jbody.get('instrument') is not None: parsed_body['instrument'] = \ jbody.get('instrument') if jbody.get('time') is not None: print("found time") parsed_body['time'] = \ jbody.get('time') if jbody.get('unixTime') is not None: print("found unixTime") parsed_body['unixTime'] = \ jbody.get('unixTime') if jbody.get('price') is not None: print("found price") parsed_body['price'] = \ jbody.get('price') if jbody.get('bucketWidth') is not None: print("found bucketWidth") parsed_body['bucketWidth'] = \ jbody.get('bucketWidth') if jbody.get('buckets') is not None: print("found buckets") parsed_body['buckets'] = [ self.ctx.instrument.Candlestick.from_dict(d, self.ctx) for d in jbody.get('buckets') ] elif str(response.status) == "400": if jbody.get('errorCode') is not None: parsed_body['errorCode'] = \ jbody.get('errorCode') if jbody.get('errorMessage') is not None: parsed_body['errorMessage'] = \ jbody.get('errorMessage') elif str(response.status) == "401": if jbody.get('errorCode') is not None: parsed_body['errorCode'] = \ jbody.get('errorCode') if jbody.get('errorMessage') is not None: parsed_body['errorMessage'] = \ jbody.get('errorMessage') elif str(response.status) == "404": if jbody.get('errorCode') is not None: parsed_body['errorCode'] = \ jbody.get('errorCode') if jbody.get('errorMessage') is not None: parsed_body['errorMessage'] = \ jbody.get('errorMessage') elif str(response.status) == "405": if jbody.get('errorCode') is not None: parsed_body['errorCode'] = \ jbody.get('errorCode') if jbody.get('errorMessage') is not None: parsed_body['errorMessage'] = \ jbody.get('errorMessage') # # Unexpected response status # else: parsed_body = jbody response.body = parsed_body return response
def candles(self, instrument, **kwargs): """Get Candlesticks Fetch candlestick data for an instrument. Parameters ---------- instrument : Instrument to get candlestick data for price : string, optional The Price component(s) to get candlestick data for. Can contain any combination of the characters "M" (midpoint candles) "B" (bid candles) and "A" (ask candles). granularity : , optional The granularity of the candlesticks to fetch count : integer, optional The number of candlesticks to return in the reponse. Count should not be specified if both the start and end parameters are provided, as the time range combined with the graularity will determine the number of candlesticks to return. fromTime : , optional The start of the time range to fetch candlesticks for. toTime : , optional The end of the time range to fetch candlesticks for. smooth : boolean, optional A flag that controls whether the candlestick is "smoothed" or not. A smoothed candlestick uses the previous candle's close price as its open price, while an unsmoothed candlestick uses the first price from its time range as its open price. includeFirst : boolean, optional A flag that controls whether the candlestick that is covered by the from time should be included in the results. This flag enables clients to use the timestamp of the last completed candlestick received to poll for future candlesticks but avoid receiving the previous candlestick repeatedly. dailyAlignment : integer, optional The hour of the day (in the specified timezone) to use for granularities that have daily alignments. alignmentTimezone : string, optional The timezone to use for the dailyAlignment parameter. Candlesticks with daily alignment will be aligned to the dailyAlignment hour within the alignmentTimezone. weeklyAlignment : , optional The day of the week used for granularities that have weekly alignment. """ request = Request('GET', '/v3/instruments/{instrument}/candles') request.set_path_param('instrument', instrument) request.set_param('price', kwargs.get('price')) request.set_param('granularity', kwargs.get('granularity')) request.set_param('count', kwargs.get('count')) request.set_param('from', kwargs.get('fromTime')) request.set_param('to', kwargs.get('toTime')) request.set_param('smooth', kwargs.get('smooth')) request.set_param('includeFirst', kwargs.get('includeFirst')) request.set_param('dailyAlignment', kwargs.get('dailyAlignment')) request.set_param('alignmentTimezone', kwargs.get('alignmentTimezone')) request.set_param('weeklyAlignment', kwargs.get('weeklyAlignment')) response = self.ctx.request(request) if response.content_type is None: return response if not response.content_type.startswith("application/json"): return response jbody = json.loads(response.raw_body) parsed_body = {} if str(response.status) == "200": if jbody.get('instrument') is not None: parsed_body['instrument'] = \ jbody.get('instrument') if jbody.get('granularity') is not None: parsed_body['granularity'] = \ jbody.get('granularity') if jbody.get('candles') is not None: parsed_body['candles'] = [ Candlestick.from_dict(d) for d in jbody.get('candles') ] if str(response.status) == "400": if jbody.get('errorCode') is not None: parsed_body['errorCode'] = \ jbody.get('errorCode') if jbody.get('errorMessage') is not None: parsed_body['errorMessage'] = \ jbody.get('errorMessage') if str(response.status) == "401": if jbody.get('errorCode') is not None: parsed_body['errorCode'] = \ jbody.get('errorCode') if jbody.get('errorMessage') is not None: parsed_body['errorMessage'] = \ jbody.get('errorMessage') if str(response.status) == "404": if jbody.get('errorCode') is not None: parsed_body['errorCode'] = \ jbody.get('errorCode') if jbody.get('errorMessage') is not None: parsed_body['errorMessage'] = \ jbody.get('errorMessage') if str(response.status) == "405": if jbody.get('errorCode') is not None: parsed_body['errorCode'] = \ jbody.get('errorCode') if jbody.get('errorMessage') is not None: parsed_body['errorMessage'] = \ jbody.get('errorMessage') response.body = parsed_body return response
def stream( self, accountID, **kwargs ): """ Get a stream of Account Prices starting from when the request is made. This pricing stream does not include every single price created for the Account, but instead will provide at most 4 prices per second (every 250 milliseconds) for each instrument being requested. If more than one price is created for an instrument during the 250 millisecond window, only the price in effect at the end of the window is sent. This means that during periods of rapid price movement, subscribers to this stream will not be sent every price. Pricing windows for different connections to the price stream are not all aligned in the same way (i.e. they are not all aligned to the top of the second). This means that during periods of rapid price movement, different subscribers may observe different prices depending on their alignment. Args: accountID: Account Identifier instruments: List of Instruments to stream Prices for. snapshot: Flag that enables/disables the sending of a pricing snapshot when initially connecting to the stream. Returns: v20.response.Response containing the results from submitting the request """ request = Request( 'GET', '/v3/accounts/{accountID}/pricing/stream' ) request.set_path_param( 'accountID', accountID ) request.set_param( 'instruments', kwargs.get('instruments') ) request.set_param( 'snapshot', kwargs.get('snapshot') ) request.set_stream(True) class Parser(): def __init__(self, ctx): self.ctx = ctx def __call__(self, line): j = json.loads(line.decode('utf-8')) type = j.get("type") if type is None: return ( "pricing.ClientPrice", self.ctx.pricing.ClientPrice.from_dict(j, self.ctx) ) elif type == "HEARTBEAT": return ( "pricing.PricingHeartbeat", self.ctx.pricing.PricingHeartbeat.from_dict(j, self.ctx) ) return ( "pricing.ClientPrice", self.ctx.pricing.ClientPrice.from_dict(j, self.ctx) ) request.set_line_parser( Parser(self.ctx) ) response = self.ctx.request(request) return response
def list(self, accountID, **kwargs): """ Get a list of Trades for an Account Args: accountID: Account Identifier ids: List of Trade IDs to retrieve. state: The state to filter the requested Trades by. instrument: The instrument to filter the requested Trades by. count: The maximum number of Trades to return. beforeID: The maximum Trade ID to return. If not provided the most recent Trades in the Account are returned. Returns: v20.response.Response containing the results from submitting the request """ request = Request('GET', '/v3/accounts/{accountID}/trades') request.set_path_param('accountID', accountID) request.set_param('ids', kwargs.get('ids')) request.set_param('state', kwargs.get('state')) request.set_param('instrument', kwargs.get('instrument')) request.set_param('count', kwargs.get('count')) request.set_param('beforeID', kwargs.get('beforeID')) response = self.ctx.request(request) if response.content_type is None: return response if not response.content_type.startswith("application/json"): return response jbody = json.loads(response.raw_body) parsed_body = {} # # Parse responses as defined by the API specification # if str(response.status) == "200": if jbody.get('trades') is not None: parsed_body['trades'] = [ self.ctx.trade.Trade.from_dict(d, self.ctx) for d in jbody.get('trades') ] if jbody.get('lastTransactionID') is not None: parsed_body['lastTransactionID'] = \ jbody.get('lastTransactionID') elif str(response.status) == "401": if jbody.get('errorCode') is not None: parsed_body['errorCode'] = \ jbody.get('errorCode') if jbody.get('errorMessage') is not None: parsed_body['errorMessage'] = \ jbody.get('errorMessage') elif str(response.status) == "404": if jbody.get('errorCode') is not None: parsed_body['errorCode'] = \ jbody.get('errorCode') if jbody.get('errorMessage') is not None: parsed_body['errorMessage'] = \ jbody.get('errorMessage') elif str(response.status) == "405": if jbody.get('errorCode') is not None: parsed_body['errorCode'] = \ jbody.get('errorCode') if jbody.get('errorMessage') is not None: parsed_body['errorMessage'] = \ jbody.get('errorMessage') # # Unexpected response status # else: parsed_body = jbody response.body = parsed_body return response
def prices( self, instrument, **kwargs ): """ Fetch a range of prices for an instrument. Accounts are not associated in any way with this endpoint. Args: instrument: Name of the Instrument fromTime: The start of the time range to fetch prices for. toTime: The end of the time range to fetch prices for. The current time is used if this parameter is not provided. Returns: v20.response.Response containing the results from submitting the request """ request = Request( 'GET', '/v3/instruments/{instrument}/price/range' ) request.set_path_param( 'instrument', instrument ) request.set_param( 'from', kwargs.get('fromTime') ) request.set_param( 'to', kwargs.get('toTime') ) response = self.ctx.request(request) if response.content_type is None: return response if not response.content_type.startswith("application/json"): return response jbody = json.loads(response.raw_body) parsed_body = {} # # Parse responses as defined by the API specification # if str(response.status) == "200": if jbody.get('prices') is not None: parsed_body['prices'] = [ self.ctx.pricing_common.Price.from_dict(d, self.ctx) for d in jbody.get('prices') ] elif str(response.status) == "400": if jbody.get('errorCode') is not None: parsed_body['errorCode'] = \ jbody.get('errorCode') if jbody.get('errorMessage') is not None: parsed_body['errorMessage'] = \ jbody.get('errorMessage') elif str(response.status) == "401": if jbody.get('errorCode') is not None: parsed_body['errorCode'] = \ jbody.get('errorCode') if jbody.get('errorMessage') is not None: parsed_body['errorMessage'] = \ jbody.get('errorMessage') elif str(response.status) == "404": if jbody.get('errorCode') is not None: parsed_body['errorCode'] = \ jbody.get('errorCode') if jbody.get('errorMessage') is not None: parsed_body['errorMessage'] = \ jbody.get('errorMessage') elif str(response.status) == "405": if jbody.get('errorCode') is not None: parsed_body['errorCode'] = \ jbody.get('errorCode') if jbody.get('errorMessage') is not None: parsed_body['errorMessage'] = \ jbody.get('errorMessage') # # Unexpected response status # else: parsed_body = jbody response.body = parsed_body return response
def base_prices(self, **kwargs): """ Get pricing information for a specified instrument. Accounts are not associated in any way with this endpoint. Args: time: The time at which the desired price for each instrument is in effect. The current price for each instrument is returned if no time is provided. Returns: v20.response.Response containing the results from submitting the request """ request = Request('GET', '/v3/pricing') request.set_param('time', kwargs.get('time')) response = self.ctx.request(request) if response.content_type is None: return response if not response.content_type.startswith("application/json"): return response jbody = json.loads(response.raw_body) parsed_body = {} # # Parse responses as defined by the API specification # if str(response.status) == "200": if jbody.get('prices') is not None: parsed_body['prices'] = [ self.ctx.pricing_common.Price.from_dict(d, self.ctx) for d in jbody.get('prices') ] elif str(response.status) == "400": if jbody.get('errorCode') is not None: parsed_body['errorCode'] = \ jbody.get('errorCode') if jbody.get('errorMessage') is not None: parsed_body['errorMessage'] = \ jbody.get('errorMessage') elif str(response.status) == "401": if jbody.get('errorCode') is not None: parsed_body['errorCode'] = \ jbody.get('errorCode') if jbody.get('errorMessage') is not None: parsed_body['errorMessage'] = \ jbody.get('errorMessage') elif str(response.status) == "404": if jbody.get('errorCode') is not None: parsed_body['errorCode'] = \ jbody.get('errorCode') if jbody.get('errorMessage') is not None: parsed_body['errorMessage'] = \ jbody.get('errorMessage') elif str(response.status) == "405": if jbody.get('errorCode') is not None: parsed_body['errorCode'] = \ jbody.get('errorCode') if jbody.get('errorMessage') is not None: parsed_body['errorMessage'] = \ jbody.get('errorMessage') # # Unexpected response status # else: parsed_body = jbody response.body = parsed_body return response
def order_book( self, instrument, **kwargs ): """ Fetch an order book for an instrument. Args: instrument: Name of the Instrument time: The time of the snapshot to fetch. If not specified, then the most recent snapshot is fetched. Returns: v20.response.Response containing the results from submitting the request """ request = Request( 'GET', '/v3/instruments/{instrument}/orderBook' ) request.set_path_param( 'instrument', instrument ) request.set_param( 'time', kwargs.get('time') ) response = self.ctx.request(request) if response.content_type is None: return response if not response.content_type.startswith("application/json"): return response jbody = json.loads(response.raw_body) parsed_body = {} # # Parse responses as defined by the API specification # if str(response.status) == "200": if jbody.get('orderBook') is not None: parsed_body['orderBook'] = \ self.ctx.instrument.OrderBook.from_dict( jbody['orderBook'], self.ctx ) elif str(response.status) == "400": if jbody.get('errorCode') is not None: parsed_body['errorCode'] = \ jbody.get('errorCode') if jbody.get('errorMessage') is not None: parsed_body['errorMessage'] = \ jbody.get('errorMessage') elif str(response.status) == "401": if jbody.get('errorCode') is not None: parsed_body['errorCode'] = \ jbody.get('errorCode') if jbody.get('errorMessage') is not None: parsed_body['errorMessage'] = \ jbody.get('errorMessage') elif str(response.status) == "404": if jbody.get('errorCode') is not None: parsed_body['errorCode'] = \ jbody.get('errorCode') if jbody.get('errorMessage') is not None: parsed_body['errorMessage'] = \ jbody.get('errorMessage') elif str(response.status) == "405": if jbody.get('errorCode') is not None: parsed_body['errorCode'] = \ jbody.get('errorCode') if jbody.get('errorMessage') is not None: parsed_body['errorMessage'] = \ jbody.get('errorMessage') # # Unexpected response status # else: parsed_body = jbody response.body = parsed_body return response
def get(self, accountID, **kwargs): """ Get pricing information for a specified list of Instruments within an Account. Args: accountID: Account Identifier instruments: List of Instruments to get pricing for. since: Date/Time filter to apply to the response. Only prices and home conversions (if requested) with a time later than this filter (i.e. the price has changed after the since time) will be provided, and are filtered independently. includeUnitsAvailable: Flag that enables the inclusion of the unitsAvailable field in the returned Price objects. includeHomeConversions: Flag that enables the inclusion of the homeConversions field in the returned response. An entry will be returned for each currency in the set of all base and quote currencies present in the requested instruments list. Returns: v20.response.Response containing the results from submitting the request """ request = Request('GET', '/v3/accounts/{accountID}/pricing') request.set_path_param('accountID', accountID) request.set_param('instruments', kwargs.get('instruments')) request.set_param('since', kwargs.get('since')) request.set_param('includeUnitsAvailable', kwargs.get('includeUnitsAvailable')) request.set_param('includeHomeConversions', kwargs.get('includeHomeConversions')) response = self.ctx.request(request) if response.content_type is None: return response if not response.content_type.startswith("application/json"): return response jbody = json.loads(response.raw_body) parsed_body = {} # # Parse responses as defined by the API specification # if str(response.status) == "200": if jbody.get('prices') is not None: parsed_body['prices'] = [ self.ctx.pricing.ClientPrice.from_dict(d, self.ctx) for d in jbody.get('prices') ] if jbody.get('homeConversions') is not None: parsed_body['homeConversions'] = [ self.ctx.pricing.HomeConversions.from_dict(d, self.ctx) for d in jbody.get('homeConversions') ] if jbody.get('time') is not None: parsed_body['time'] = \ jbody.get('time') elif str(response.status) == "400": if jbody.get('errorCode') is not None: parsed_body['errorCode'] = \ jbody.get('errorCode') if jbody.get('errorMessage') is not None: parsed_body['errorMessage'] = \ jbody.get('errorMessage') elif str(response.status) == "401": if jbody.get('errorCode') is not None: parsed_body['errorCode'] = \ jbody.get('errorCode') if jbody.get('errorMessage') is not None: parsed_body['errorMessage'] = \ jbody.get('errorMessage') elif str(response.status) == "404": if jbody.get('errorCode') is not None: parsed_body['errorCode'] = \ jbody.get('errorCode') if jbody.get('errorMessage') is not None: parsed_body['errorMessage'] = \ jbody.get('errorMessage') elif str(response.status) == "405": if jbody.get('errorCode') is not None: parsed_body['errorCode'] = \ jbody.get('errorCode') if jbody.get('errorMessage') is not None: parsed_body['errorMessage'] = \ jbody.get('errorMessage') # # Unexpected response status # else: parsed_body = jbody response.body = parsed_body return response
def get( self, accountID, **kwargs ): """Current Prices Get pricing information for a specified list of Instruments within an Account. Parameters ---------- accountID : ID of the Account to fetch current Prices for. instruments : array, optional List of Instruments to get pricing for. since : , optional Date/Time filter to apply to the returned prices. Only prices with a time later than this filter will be provided. includeUnitsAvailable : , optional Flag that enables the inclusion of the unitsAvailable field in the returned Price objects. """ request = Request( 'GET', '/v3/accounts/{accountID}/pricing' ) request.set_path_param( 'accountID', accountID ) request.set_param( 'instruments', kwargs.get('instruments') ) request.set_param( 'since', kwargs.get('since') ) request.set_param( 'includeUnitsAvailable', kwargs.get('includeUnitsAvailable') ) response = self.ctx.request(request) if response.content_type is None: return response if not response.content_type.startswith("application/json"): return response jbody = json.loads(response.raw_body) parsed_body = {} if str(response.status) == "200": if jbody.get('prices') is not None: parsed_body['prices'] = [ Price.from_dict(d) for d in jbody.get('prices') ] if str(response.status) == "400": if jbody.get('errorCode') is not None: parsed_body['errorCode'] = \ jbody.get('errorCode') if jbody.get('errorMessage') is not None: parsed_body['errorMessage'] = \ jbody.get('errorMessage') if str(response.status) == "401": if jbody.get('errorCode') is not None: parsed_body['errorCode'] = \ jbody.get('errorCode') if jbody.get('errorMessage') is not None: parsed_body['errorMessage'] = \ jbody.get('errorMessage') if str(response.status) == "404": if jbody.get('errorCode') is not None: parsed_body['errorCode'] = \ jbody.get('errorCode') if jbody.get('errorMessage') is not None: parsed_body['errorMessage'] = \ jbody.get('errorMessage') if str(response.status) == "405": if jbody.get('errorCode') is not None: parsed_body['errorCode'] = \ jbody.get('errorCode') if jbody.get('errorMessage') is not None: parsed_body['errorMessage'] = \ jbody.get('errorMessage') response.body = parsed_body return response
def candles(self, instrument, **kwargs): """ Fetch candlestick data for an instrument. Args: instrument: Name of the Instrument price: The Price component(s) to get candlestick data for. Can contain any combination of the characters "M" (midpoint candles) "B" (bid candles) and "A" (ask candles). granularity: The granularity of the candlesticks to fetch count: The number of candlesticks to return in the response. Count should not be specified if both the start and end parameters are provided, as the time range combined with the granularity will determine the number of candlesticks to return. fromTime: The start of the time range to fetch candlesticks for. toTime: The end of the time range to fetch candlesticks for. smooth: A flag that controls whether the candlestick is "smoothed" or not. A smoothed candlestick uses the previous candle's close price as its open price, while an unsmoothed candlestick uses the first price from its time range as its open price. includeFirst: A flag that controls whether the candlestick that is covered by the from time should be included in the results. This flag enables clients to use the timestamp of the last completed candlestick received to poll for future candlesticks but avoid receiving the previous candlestick repeatedly. dailyAlignment: The hour of the day (in the specified timezone) to use for granularities that have daily alignments. alignmentTimezone: The timezone to use for the dailyAlignment parameter. Candlesticks with daily alignment will be aligned to the dailyAlignment hour within the alignmentTimezone. Note that the returned times will still be represented in UTC. weeklyAlignment: The day of the week used for granularities that have weekly alignment. units: The number of units used to calculate the volume-weighted average bid and ask prices in the returned candles. Returns: v20.response.Response containing the results from submitting the request """ request = Request( 'GET', '/v3/accounts/{accountID}/instruments/{instrument}/candles') request.set_path_param('instrument', instrument) request.set_param('price', kwargs.get('price')) request.set_param('granularity', kwargs.get('granularity')) request.set_param('count', kwargs.get('count')) request.set_param('from', kwargs.get('fromTime')) request.set_param('to', kwargs.get('toTime')) request.set_param('smooth', kwargs.get('smooth')) request.set_param('includeFirst', kwargs.get('includeFirst')) request.set_param('dailyAlignment', kwargs.get('dailyAlignment')) request.set_param('alignmentTimezone', kwargs.get('alignmentTimezone')) request.set_param('weeklyAlignment', kwargs.get('weeklyAlignment')) request.set_param('units', kwargs.get('units')) response = self.ctx.request(request) if response.content_type is None: return response if not response.content_type.startswith("application/json"): return response jbody = json.loads(response.raw_body) parsed_body = {} # # Parse responses as defined by the API specification # if str(response.status) == "200": if jbody.get('instrument') is not None: parsed_body['instrument'] = \ jbody.get('instrument') if jbody.get('granularity') is not None: parsed_body['granularity'] = \ jbody.get('granularity') if jbody.get('candles') is not None: parsed_body['candles'] = [ self.ctx.instrument.Candlestick.from_dict(d, self.ctx) for d in jbody.get('candles') ] elif str(response.status) == "400": if jbody.get('errorCode') is not None: parsed_body['errorCode'] = \ jbody.get('errorCode') if jbody.get('errorMessage') is not None: parsed_body['errorMessage'] = \ jbody.get('errorMessage') elif str(response.status) == "401": if jbody.get('errorCode') is not None: parsed_body['errorCode'] = \ jbody.get('errorCode') if jbody.get('errorMessage') is not None: parsed_body['errorMessage'] = \ jbody.get('errorMessage') elif str(response.status) == "404": if jbody.get('errorCode') is not None: parsed_body['errorCode'] = \ jbody.get('errorCode') if jbody.get('errorMessage') is not None: parsed_body['errorMessage'] = \ jbody.get('errorMessage') elif str(response.status) == "405": if jbody.get('errorCode') is not None: parsed_body['errorCode'] = \ jbody.get('errorCode') if jbody.get('errorMessage') is not None: parsed_body['errorMessage'] = \ jbody.get('errorMessage') # # Unexpected response status # else: parsed_body = jbody response.body = parsed_body return response
def base_prices( self, **kwargs ): """ Get pricing information for a specified instrument. Accounts are not associated in any way with this endpoint. Args: time: The time at which the desired price for each instrument is in effect. The current price for each instrument is returned if no time is provided. Returns: v20.response.Response containing the results from submitting the request """ request = Request( 'GET', '/v3/pricing' ) request.set_param( 'time', kwargs.get('time') ) response = self.ctx.request(request) if response.content_type is None: return response if not response.content_type.startswith("application/json"): return response jbody = json.loads(response.raw_body) parsed_body = {} # # Parse responses as defined by the API specification # if str(response.status) == "200": if jbody.get('prices') is not None: parsed_body['prices'] = [ self.ctx.pricing_common.Price.from_dict(d, self.ctx) for d in jbody.get('prices') ] elif str(response.status) == "400": if jbody.get('errorCode') is not None: parsed_body['errorCode'] = \ jbody.get('errorCode') if jbody.get('errorMessage') is not None: parsed_body['errorMessage'] = \ jbody.get('errorMessage') elif str(response.status) == "401": if jbody.get('errorCode') is not None: parsed_body['errorCode'] = \ jbody.get('errorCode') if jbody.get('errorMessage') is not None: parsed_body['errorMessage'] = \ jbody.get('errorMessage') elif str(response.status) == "404": if jbody.get('errorCode') is not None: parsed_body['errorCode'] = \ jbody.get('errorCode') if jbody.get('errorMessage') is not None: parsed_body['errorMessage'] = \ jbody.get('errorMessage') elif str(response.status) == "405": if jbody.get('errorCode') is not None: parsed_body['errorCode'] = \ jbody.get('errorCode') if jbody.get('errorMessage') is not None: parsed_body['errorMessage'] = \ jbody.get('errorMessage') # # Unexpected response status # else: parsed_body = jbody response.body = parsed_body return response