diff --git a/src/ChangeLog b/src/ChangeLog index 43e2ee6..a7d383e 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,5 +1,23 @@ OANDA v20 API Change Log +Version 3.0.25 (September 28, 2018) + + * All - Added orderBook and PositionBook endpoints. Issue#29 + (https://github.com/oanda/v20-python/issues/29) + + +Version 3.0.24 (May 11, 2018) + + * Java - Added support for Accept-Datetime-Format and additional + custom headers. Issue#8 (https://github.com/oanda/v20-java/issues/8) + + +Version 3.0.23 (May 04, 2018) + + * Java - Fixed using null in a TradeSetDependentOrdersRequest Issue#7 + (https://github.com/oanda/v20-java/issues/7) + + Version 3.0.22 (April 11, 2018) * Various documentation and example improvements diff --git a/src/account.js b/src/account.js index 95cb371..ed19a9e 100644 --- a/src/account.js +++ b/src/account.js @@ -162,6 +162,13 @@ const Account_Properties = [ 'primitive', 'boolean' ), + new Property( + 'lastOrderFillTimestamp', + "Last Order Fill timestamp.", + "The date/time of the last order that was filled for this account.", + 'primitive', + 'primitives.DateTime' + ), new Property( 'unrealizedPL', "Unrealized Profit/Loss", @@ -379,6 +386,10 @@ class Account extends Definition { this.hedgingEnabled = data['hedgingEnabled']; } + if (data['lastOrderFillTimestamp'] !== undefined) { + this.lastOrderFillTimestamp = data['lastOrderFillTimestamp']; + } + if (data['unrealizedPL'] !== undefined) { this.unrealizedPL = data['unrealizedPL']; } @@ -843,6 +854,13 @@ const AccountSummary_Properties = [ 'primitive', 'boolean' ), + new Property( + 'lastOrderFillTimestamp', + "Last Order Fill timestamp.", + "The date/time of the last order that was filled for this account.", + 'primitive', + 'primitives.DateTime' + ), new Property( 'unrealizedPL', "Unrealized Profit/Loss", @@ -1039,6 +1057,10 @@ class AccountSummary extends Definition { this.hedgingEnabled = data['hedgingEnabled']; } + if (data['lastOrderFillTimestamp'] !== undefined) { + this.lastOrderFillTimestamp = data['lastOrderFillTimestamp']; + } + if (data['unrealizedPL'] !== undefined) { this.unrealizedPL = data['unrealizedPL']; } diff --git a/src/context.js b/src/context.js index b0aa7df..6911f2c 100644 --- a/src/context.js +++ b/src/context.js @@ -2,16 +2,17 @@ "use strict"; -var account = require("./account"); -var order = require("./order"); +var instrument = require("./instrument"); var position = require("./position"); -var user = require("./user"); +var trade = require("./trade"); +var site = require("./site"); +var primitives = require("./primitives"); +var account = require("./account"); var transaction = require("./transaction"); +var user = require("./user"); var pricing = require("./pricing"); -var primitives = require("./primitives"); -var site = require("./site"); -var trade = require("./trade"); -var instrument = require("./instrument"); +var order = require("./order"); +var pricing_common = require("./pricing_common"); class Response { @@ -67,7 +68,7 @@ class Context { this.headers = { "Content-Type": "application/json", - "OANDA-Agent" : `v20-javascript/3.0.22 (${application})` + "OANDA-Agent" : `v20-javascript/3.0.25 (${application})` }; this.token = ""; @@ -81,16 +82,17 @@ class Context { this.http = require('http'); } - this.account = new account.EntitySpec(this); - this.order = new order.EntitySpec(this); + this.instrument = new instrument.EntitySpec(this); this.position = new position.EntitySpec(this); - this.user = new user.EntitySpec(this); + this.trade = new trade.EntitySpec(this); + this.site = new site.EntitySpec(this); + this.primitives = new primitives.EntitySpec(this); + this.account = new account.EntitySpec(this); this.transaction = new transaction.EntitySpec(this); + this.user = new user.EntitySpec(this); this.pricing = new pricing.EntitySpec(this); - this.primitives = new primitives.EntitySpec(this); - this.site = new site.EntitySpec(this); - this.trade = new trade.EntitySpec(this); - this.instrument = new instrument.EntitySpec(this); + this.order = new order.EntitySpec(this); + this.pricing_common = new pricing_common.EntitySpec(this); } setToken(token) { diff --git a/src/instrument.js b/src/instrument.js index 7394977..acf34c3 100644 --- a/src/instrument.js +++ b/src/instrument.js @@ -6,6 +6,7 @@ var Definition = require('./base').Definition; var Property = require('./base').Property; var Field = require('./base').Field; +var pricing_common = require('./pricing_common'); @@ -99,28 +100,28 @@ const CandlestickData_Properties = [ 'o', "The first (open) price in the time-range represented by the candlestick.", 'primitive', - 'pricing.PriceValue' + 'pricing_common.PriceValue' ), new Property( 'h', 'h', "The highest price in the time-range represented by the candlestick.", 'primitive', - 'pricing.PriceValue' + 'pricing_common.PriceValue' ), new Property( 'l', 'l', "The lowest price in the time-range represented by the candlestick.", 'primitive', - 'pricing.PriceValue' + 'pricing_common.PriceValue' ), new Property( 'c', 'c', "The last (closing) price in the time-range represented by the candlestick.", 'primitive', - 'pricing.PriceValue' + 'pricing_common.PriceValue' ), ]; @@ -175,14 +176,14 @@ const OrderBook_Properties = [ 'price', "The price (midpoint) for the order book's instrument at the time of the order book snapshot", 'primitive', - 'pricing.PriceValue' + 'pricing_common.PriceValue' ), new Property( 'bucketWidth', 'bucketWidth', "The price width for each bucket. Each bucket covers the price range from the bucket's price to the bucket's price + bucketWidth.", 'primitive', - 'pricing.PriceValue' + 'pricing_common.PriceValue' ), new Property( 'buckets', @@ -234,7 +235,7 @@ const OrderBookBucket_Properties = [ 'price', "The lowest price (inclusive) covered by the bucket. The bucket covers the price range from the price to price + the order book's bucketWidth.", 'primitive', - 'pricing.PriceValue' + 'pricing_common.PriceValue' ), new Property( 'longCountPercent', @@ -299,14 +300,14 @@ const PositionBook_Properties = [ 'price', "The price (midpoint) for the position book's instrument at the time of the position book snapshot", 'primitive', - 'pricing.PriceValue' + 'pricing_common.PriceValue' ), new Property( 'bucketWidth', 'bucketWidth', "The price width for each bucket. Each bucket covers the price range from the bucket's price to the bucket's price + bucketWidth.", 'primitive', - 'pricing.PriceValue' + 'pricing_common.PriceValue' ), new Property( 'buckets', @@ -358,7 +359,7 @@ const PositionBookBucket_Properties = [ 'price', "The lowest price (inclusive) covered by the bucket. The bucket covers the price range from the price to price + the position book's bucketWidth.", 'primitive', - 'pricing.PriceValue' + 'pricing_common.PriceValue' ), new Property( 'longCountPercent', @@ -528,6 +529,325 @@ class EntitySpec { ); } + price( + instrument, + queryParams, + responseHandler + ) + { + if (!responseHandler) + { + throw "No responseHandler provided for API call" + } + + + let path = '/v3/instruments/{instrument}/price'; + + queryParams = queryParams || {}; + + path = path.replace('{' + 'instrument' + '}', instrument); + + path = path + "?"; + if (typeof queryParams['time'] !== 'undefined') { + path = path + "time=" + queryParams['time'] + "&"; + } + + let body = {}; + + let handleResponse = (response) => { + if (response.contentType.startsWith("application/json")) + { + let msg = JSON.parse(response.rawBody); + + response.body = {}; + + if (response.statusCode == 200) + { + if (msg['price'] !== undefined) { + response.body.price = new pricing_common.Price(msg['price']); + } + + } + else if (response.statusCode == 400) + { + } + else if (response.statusCode == 401) + { + } + else if (response.statusCode == 404) + { + } + else if (response.statusCode == 405) + { + } + // + // Assume standard error response with errorCode and errorMessage + // + else + { + if (msg['errorCode'] !== undefined) { + response.body.errorCode = msg['errorCode']; + } + + if (msg['errorMessage'] !== undefined) { + response.body.errorMessage = msg['errorMessage']; + } + } + } + + responseHandler(response); + }; + + + this.context.request( + 'GET', + path, + body, + undefined, + handleResponse + ); + } + + prices( + instrument, + queryParams, + responseHandler + ) + { + if (!responseHandler) + { + throw "No responseHandler provided for API call" + } + + + let path = '/v3/instruments/{instrument}/price/range'; + + queryParams = queryParams || {}; + + path = path.replace('{' + 'instrument' + '}', instrument); + + path = path + "?"; + if (typeof queryParams['from'] !== 'undefined') { + path = path + "from=" + queryParams['from'] + "&"; + } + if (typeof queryParams['to'] !== 'undefined') { + path = path + "to=" + queryParams['to'] + "&"; + } + + let body = {}; + + let handleResponse = (response) => { + if (response.contentType.startsWith("application/json")) + { + let msg = JSON.parse(response.rawBody); + + response.body = {}; + + if (response.statusCode == 200) + { + if (msg['prices'] !== undefined) { + response.body.prices = msg['prices'].map(x => new pricing_common.Price(x)); + } + + } + else if (response.statusCode == 400) + { + } + else if (response.statusCode == 401) + { + } + else if (response.statusCode == 404) + { + } + else if (response.statusCode == 405) + { + } + // + // Assume standard error response with errorCode and errorMessage + // + else + { + if (msg['errorCode'] !== undefined) { + response.body.errorCode = msg['errorCode']; + } + + if (msg['errorMessage'] !== undefined) { + response.body.errorMessage = msg['errorMessage']; + } + } + } + + responseHandler(response); + }; + + + this.context.request( + 'GET', + path, + body, + undefined, + handleResponse + ); + } + + orderBook( + instrument, + queryParams, + responseHandler + ) + { + if (!responseHandler) + { + throw "No responseHandler provided for API call" + } + + + let path = '/v3/instruments/{instrument}/orderBook'; + + queryParams = queryParams || {}; + + path = path.replace('{' + 'instrument' + '}', instrument); + + path = path + "?"; + if (typeof queryParams['time'] !== 'undefined') { + path = path + "time=" + queryParams['time'] + "&"; + } + + let body = {}; + + let handleResponse = (response) => { + if (response.contentType.startsWith("application/json")) + { + let msg = JSON.parse(response.rawBody); + + response.body = {}; + + if (response.statusCode == 200) + { + if (msg['orderBook'] !== undefined) { + response.body.orderBook = new OrderBook(msg['orderBook']); + } + + } + else if (response.statusCode == 400) + { + } + else if (response.statusCode == 401) + { + } + else if (response.statusCode == 404) + { + } + else if (response.statusCode == 405) + { + } + // + // Assume standard error response with errorCode and errorMessage + // + else + { + if (msg['errorCode'] !== undefined) { + response.body.errorCode = msg['errorCode']; + } + + if (msg['errorMessage'] !== undefined) { + response.body.errorMessage = msg['errorMessage']; + } + } + } + + responseHandler(response); + }; + + + this.context.request( + 'GET', + path, + body, + undefined, + handleResponse + ); + } + + positionBook( + instrument, + queryParams, + responseHandler + ) + { + if (!responseHandler) + { + throw "No responseHandler provided for API call" + } + + + let path = '/v3/instruments/{instrument}/positionBook'; + + queryParams = queryParams || {}; + + path = path.replace('{' + 'instrument' + '}', instrument); + + path = path + "?"; + if (typeof queryParams['time'] !== 'undefined') { + path = path + "time=" + queryParams['time'] + "&"; + } + + let body = {}; + + let handleResponse = (response) => { + if (response.contentType.startsWith("application/json")) + { + let msg = JSON.parse(response.rawBody); + + response.body = {}; + + if (response.statusCode == 200) + { + if (msg['positionBook'] !== undefined) { + response.body.positionBook = new PositionBook(msg['positionBook']); + } + + } + else if (response.statusCode == 400) + { + } + else if (response.statusCode == 401) + { + } + else if (response.statusCode == 404) + { + } + else if (response.statusCode == 405) + { + } + // + // Assume standard error response with errorCode and errorMessage + // + else + { + if (msg['errorCode'] !== undefined) { + response.body.errorCode = msg['errorCode']; + } + + if (msg['errorMessage'] !== undefined) { + response.body.errorMessage = msg['errorMessage']; + } + } + } + + responseHandler(response); + }; + + + this.context.request( + 'GET', + path, + body, + undefined, + handleResponse + ); + } + } diff --git a/src/order.js b/src/order.js index faa651c..c8116d3 100644 --- a/src/order.js +++ b/src/order.js @@ -64,14 +64,14 @@ const DynamicOrderState_Properties = [ "Trailing Stop Value", "The Order's calculated trailing stop value.", 'primitive', - 'pricing.PriceValue' + 'pricing_common.PriceValue' ), new Property( 'triggerDistance', "Trigger Distance", "The distance between the Trailing Stop Loss Order's trailingStopValue and the current Market Price. This represents the distance (in price units) of the Order from a triggering price. If the distance could not be determined, this value will not be set.", 'primitive', - 'pricing.PriceValue' + 'pricing_common.PriceValue' ), new Property( 'isTriggerDistanceExact', @@ -179,6 +179,18 @@ class Order extends Definition { { return new Order(order); } + else if (order["type"] == "TAKE_PROFIT") + { + return new TakeProfitOrder(order); + } + else if (order["type"] == "STOP_LOSS") + { + return new StopLossOrder(order); + } + else if (order["type"] == "TRAILING_STOP_LOSS") + { + return new TrailingStopLossOrder(order); + } else if (order["type"] == "MARKET") { return new MarketOrder(order); @@ -199,18 +211,6 @@ class Order extends Definition { { return new MarketIfTouchedOrder(order); } - else if (order["type"] == "TAKE_PROFIT") - { - return new TakeProfitOrder(order); - } - else if (order["type"] == "STOP_LOSS") - { - return new StopLossOrder(order); - } - else if (order["type"] == "TRAILING_STOP_LOSS") - { - return new TrailingStopLossOrder(order); - } return new Order(order); } @@ -278,7 +278,7 @@ const MarketOrder_Properties = [ "Price Bound", "The worst price that the client is willing to have the Market Order filled at.", 'primitive', - 'pricing.PriceValue' + 'pricing_common.PriceValue' ), new Property( 'positionFill', @@ -584,7 +584,7 @@ const FixedPriceOrder_Properties = [ "Price", "The price specified for the Fixed Price Order. This price is the exact price that the Fixed Price Order will be filled at.", 'primitive', - 'pricing.PriceValue' + 'pricing_common.PriceValue' ), new Property( 'positionFill', @@ -839,7 +839,7 @@ const LimitOrder_Properties = [ "Price", "The price threshold specified for the Limit Order. The Limit Order will only be filled by a market price that is equal to or better than this price.", 'primitive', - 'pricing.PriceValue' + 'pricing_common.PriceValue' ), new Property( 'timeInForce', @@ -1144,14 +1144,14 @@ const StopOrder_Properties = [ "Price", "The price threshold specified for the Stop Order. The Stop Order will only be filled by a market price that is equal to or worse than this price.", 'primitive', - 'pricing.PriceValue' + 'pricing_common.PriceValue' ), new Property( 'priceBound', "Price Bound", "The worst market price that may be used to fill this Stop Order. If the market gaps and crosses through both the price and the priceBound, the Stop Order will be cancelled instead of being filled.", 'primitive', - 'pricing.PriceValue' + 'pricing_common.PriceValue' ), new Property( 'timeInForce', @@ -1460,14 +1460,14 @@ const MarketIfTouchedOrder_Properties = [ "Price", "The price threshold specified for the MarketIfTouched Order. The MarketIfTouched Order will only be filled by a market price that crosses this price from the direction of the market price at the time when the Order was created (the initialMarketPrice). Depending on the value of the Order's price and initialMarketPrice, the MarketIfTouchedOrder will behave like a Limit or a Stop Order.", 'primitive', - 'pricing.PriceValue' + 'pricing_common.PriceValue' ), new Property( 'priceBound', "Price Value", "The worst market price that may be used to fill this MarketIfTouched Order.", 'primitive', - 'pricing.PriceValue' + 'pricing_common.PriceValue' ), new Property( 'timeInForce', @@ -1502,7 +1502,7 @@ const MarketIfTouchedOrder_Properties = [ "Initial Market Price", "The Market price at the time when the MarketIfTouched Order was created.", 'primitive', - 'pricing.PriceValue' + 'pricing_common.PriceValue' ), new Property( 'takeProfitOnFill', @@ -1787,7 +1787,7 @@ const TakeProfitOrder_Properties = [ "Price", "The price threshold specified for the TakeProfit Order. The associated Trade will be closed by a market price that is equal to or better than this threshold.", 'primitive', - 'pricing.PriceValue' + 'pricing_common.PriceValue' ), new Property( 'timeInForce', @@ -2041,7 +2041,7 @@ const StopLossOrder_Properties = [ "Price", "The price threshold specified for the Stop Loss Order. If the guaranteed flag is false, the associated Trade will be closed by a market price that is equal to or worse than this threshold. If the flag is true the associated Trade will be closed at this price.", 'primitive', - 'pricing.PriceValue' + 'pricing_common.PriceValue' ), new Property( 'distance', @@ -2342,7 +2342,7 @@ const TrailingStopLossOrder_Properties = [ "Trailing Stop Loss Value", "The trigger price for the Trailing Stop Loss Order. The trailing stop value will trail (follow) the market price by the TSL order's configured \"distance\" as the market price moves in the winning direction. If the market price moves to a level that is equal to or worse than the trailing stop value, the order will be filled and the Trade will be closed.", 'primitive', - 'pricing.PriceValue' + 'pricing_common.PriceValue' ), new Property( 'fillingTransactionID', @@ -2569,7 +2569,7 @@ const MarketOrderRequest_Properties = [ "Price Bound", "The worst price that the client is willing to have the Market Order filled at.", 'primitive', - 'pricing.PriceValue' + 'pricing_common.PriceValue' ), new Property( 'positionFill', @@ -2710,7 +2710,7 @@ const LimitOrderRequest_Properties = [ "Price", "The price threshold specified for the Limit Order. The Limit Order will only be filled by a market price that is equal to or better than this price.", 'primitive', - 'pricing.PriceValue' + 'pricing_common.PriceValue' ), new Property( 'timeInForce', @@ -2883,14 +2883,14 @@ const StopOrderRequest_Properties = [ "Price", "The price threshold specified for the Stop Order. The Stop Order will only be filled by a market price that is equal to or worse than this price.", 'primitive', - 'pricing.PriceValue' + 'pricing_common.PriceValue' ), new Property( 'priceBound', "Price Bound", "The worst market price that may be used to fill this Stop Order. If the market gaps and crosses through both the price and the priceBound, the Stop Order will be cancelled instead of being filled.", 'primitive', - 'pricing.PriceValue' + 'pricing_common.PriceValue' ), new Property( 'timeInForce', @@ -3067,14 +3067,14 @@ const MarketIfTouchedOrderRequest_Properties = [ "Price", "The price threshold specified for the MarketIfTouched Order. The MarketIfTouched Order will only be filled by a market price that crosses this price from the direction of the market price at the time when the Order was created (the initialMarketPrice). Depending on the value of the Order's price and initialMarketPrice, the MarketIfTouchedOrder will behave like a Limit or a Stop Order.", 'primitive', - 'pricing.PriceValue' + 'pricing_common.PriceValue' ), new Property( 'priceBound', "Price Value", "The worst market price that may be used to fill this MarketIfTouched Order.", 'primitive', - 'pricing.PriceValue' + 'pricing_common.PriceValue' ), new Property( 'timeInForce', @@ -3251,7 +3251,7 @@ const TakeProfitOrderRequest_Properties = [ "Price", "The price threshold specified for the TakeProfit Order. The associated Trade will be closed by a market price that is equal to or better than this threshold.", 'primitive', - 'pricing.PriceValue' + 'pricing_common.PriceValue' ), new Property( 'timeInForce', @@ -3366,7 +3366,7 @@ const StopLossOrderRequest_Properties = [ "Price", "The price threshold specified for the Stop Loss Order. If the guaranteed flag is false, the associated Trade will be closed by a market price that is equal to or worse than this threshold. If the flag is true the associated Trade will be closed at this price.", 'primitive', - 'pricing.PriceValue' + 'pricing_common.PriceValue' ), new Property( 'distance', diff --git a/src/package.json b/src/package.json index f6d82e0..0025025 100644 --- a/src/package.json +++ b/src/package.json @@ -1,7 +1,7 @@ { "name": "@oanda/v20", "description": "OANDA v20 bindings for Javascript", - "version": "3.0.22-0", + "version": "3.0.25-0", "author": "OANDA Corporation", "license": "MIT", "homepage": "http://developer.oanda.com/rest-live-v20/introduction" diff --git a/src/position.js b/src/position.js index 27ce436..9319c79 100644 --- a/src/position.js +++ b/src/position.js @@ -151,7 +151,7 @@ const PositionSide_Properties = [ "Average Price", "Volume-weighted average of the underlying Trade open prices for the Position.", 'primitive', - 'pricing.PriceValue' + 'pricing_common.PriceValue' ), new Property( 'tradeIDs', diff --git a/src/pricing.js b/src/pricing.js index 49255b8..bb45af9 100644 --- a/src/pricing.js +++ b/src/pricing.js @@ -6,11 +6,13 @@ var Definition = require('./base').Definition; var Property = require('./base').Property; var Field = require('./base').Field; +var pricing_common = require('./pricing_common'); var order = require('./order'); +var instrument = require('./instrument'); -const Price_Properties = [ +const ClientPrice_Properties = [ new Property( 'type', "Type", @@ -65,14 +67,14 @@ const Price_Properties = [ "Closeout Bid", "The closeout bid Price. This Price is used when a bid is required to closeout a Position (margin closeout or manual) yet there is no bid liquidity. The closeout bid is never used to open a new position.", 'primitive', - 'pricing.PriceValue' + 'pricing_common.PriceValue' ), new Property( 'closeoutAsk', "Closeout Ask", "The closeout ask Price. This Price is used when a ask is required to closeout a Position (margin closeout or manual) yet there is no ask liquidity. The closeout ask is never used to open a new position.", 'primitive', - 'pricing.PriceValue' + 'pricing_common.PriceValue' ), new Property( 'quoteHomeConversionFactors', @@ -90,7 +92,7 @@ const Price_Properties = [ ), ]; -class Price extends Definition { +class ClientPrice extends Definition { constructor(data) { super(); @@ -98,7 +100,7 @@ class Price extends Definition { this._nameFormat = ""; - this._properties = Price_Properties; + this._properties = ClientPrice_Properties; data = data || {}; @@ -126,11 +128,11 @@ class Price extends Definition { } if (data['bids'] !== undefined) { - this.bids = data['bids'].map(x => new PriceBucket(x)); + this.bids = data['bids'].map(x => new pricing_common.PriceBucket(x)); } if (data['asks'] !== undefined) { - this.asks = data['asks'].map(x => new PriceBucket(x)); + this.asks = data['asks'].map(x => new pricing_common.PriceBucket(x)); } if (data['closeoutBid'] !== undefined) { @@ -152,46 +154,6 @@ class Price extends Definition { } } -const PriceBucket_Properties = [ - new Property( - 'price', - "Price", - "The Price offered by the PriceBucket", - 'primitive', - 'pricing.PriceValue' - ), - new Property( - 'liquidity', - "Liquidity", - "The amount of liquidity offered by the PriceBucket", - 'primitive', - 'integer' - ), -]; - -class PriceBucket extends Definition { - constructor(data) { - super(); - - this._summaryFormat = ""; - - this._nameFormat = ""; - - this._properties = PriceBucket_Properties; - - data = data || {}; - - if (data['price'] !== undefined) { - this.price = data['price']; - } - - if (data['liquidity'] !== undefined) { - this.liquidity = data['liquidity']; - } - - } -} - const QuoteHomeConversionFactors_Properties = [ new Property( 'positiveUnits', @@ -294,79 +256,6 @@ class HomeConversions extends Definition { } } -const ClientPrice_Properties = [ - new Property( - 'bids', - "Bids", - "The list of prices and liquidity available on the Instrument's bid side. It is possible for this list to be empty if there is no bid liquidity currently available for the Instrument in the Account.", - 'array_object', - 'PriceBucket' - ), - new Property( - 'asks', - "Asks", - "The list of prices and liquidity available on the Instrument's ask side. It is possible for this list to be empty if there is no ask liquidity currently available for the Instrument in the Account.", - 'array_object', - 'PriceBucket' - ), - new Property( - 'closeoutBid', - "Closeout Bid", - "The closeout bid Price. This Price is used when a bid is required to closeout a Position (margin closeout or manual) yet there is no bid liquidity. The closeout bid is never used to open a new position.", - 'primitive', - 'pricing.PriceValue' - ), - new Property( - 'closeoutAsk', - "Closeout Ask", - "The closeout ask Price. This Price is used when a ask is required to closeout a Position (margin closeout or manual) yet there is no ask liquidity. The closeout ask is never used to open a new position.", - 'primitive', - 'pricing.PriceValue' - ), - new Property( - 'timestamp', - "Timestamp", - "The date/time when the Price was created.", - 'primitive', - 'primitives.DateTime' - ), -]; - -class ClientPrice extends Definition { - constructor(data) { - super(); - - this._summaryFormat = ""; - - this._nameFormat = ""; - - this._properties = ClientPrice_Properties; - - data = data || {}; - - if (data['bids'] !== undefined) { - this.bids = data['bids'].map(x => new PriceBucket(x)); - } - - if (data['asks'] !== undefined) { - this.asks = data['asks'].map(x => new PriceBucket(x)); - } - - if (data['closeoutBid'] !== undefined) { - this.closeoutBid = data['closeoutBid']; - } - - if (data['closeoutAsk'] !== undefined) { - this.closeoutAsk = data['closeoutAsk']; - } - - if (data['timestamp'] !== undefined) { - this.timestamp = data['timestamp']; - } - - } -} - const PricingHeartbeat_Properties = [ new Property( 'type', @@ -413,14 +302,171 @@ class PricingHeartbeat extends Definition { class EntitySpec { constructor(context) { this.context = context; - this.Price = Price; - this.PriceBucket = PriceBucket; + this.ClientPrice = ClientPrice; this.QuoteHomeConversionFactors = QuoteHomeConversionFactors; this.HomeConversions = HomeConversions; - this.ClientPrice = ClientPrice; this.PricingHeartbeat = PricingHeartbeat; } + basePrices( + queryParams, + responseHandler + ) + { + if (!responseHandler) + { + throw "No responseHandler provided for API call" + } + + + let path = '/v3/pricing'; + + queryParams = queryParams || {}; + + + path = path + "?"; + if (typeof queryParams['time'] !== 'undefined') { + path = path + "time=" + queryParams['time'] + "&"; + } + + let body = {}; + + let handleResponse = (response) => { + if (response.contentType.startsWith("application/json")) + { + let msg = JSON.parse(response.rawBody); + + response.body = {}; + + if (response.statusCode == 200) + { + if (msg['prices'] !== undefined) { + response.body.prices = msg['prices'].map(x => new pricing_common.Price(x)); + } + + } + else if (response.statusCode == 400) + { + } + else if (response.statusCode == 401) + { + } + else if (response.statusCode == 404) + { + } + else if (response.statusCode == 405) + { + } + // + // Assume standard error response with errorCode and errorMessage + // + else + { + if (msg['errorCode'] !== undefined) { + response.body.errorCode = msg['errorCode']; + } + + if (msg['errorMessage'] !== undefined) { + response.body.errorMessage = msg['errorMessage']; + } + } + } + + responseHandler(response); + }; + + + this.context.request( + 'GET', + path, + body, + undefined, + handleResponse + ); + } + + getPriceRange( + instrument, + queryParams, + responseHandler + ) + { + if (!responseHandler) + { + throw "No responseHandler provided for API call" + } + + + let path = '/v3/pricing/range'; + + queryParams = queryParams || {}; + + path = path.replace('{' + 'instrument' + '}', instrument); + + path = path + "?"; + if (typeof queryParams['from'] !== 'undefined') { + path = path + "from=" + queryParams['from'] + "&"; + } + if (typeof queryParams['to'] !== 'undefined') { + path = path + "to=" + queryParams['to'] + "&"; + } + + let body = {}; + + let handleResponse = (response) => { + if (response.contentType.startsWith("application/json")) + { + let msg = JSON.parse(response.rawBody); + + response.body = {}; + + if (response.statusCode == 200) + { + if (msg['prices'] !== undefined) { + response.body.prices = msg['prices'].map(x => new pricing_common.Price(x)); + } + + } + else if (response.statusCode == 400) + { + } + else if (response.statusCode == 401) + { + } + else if (response.statusCode == 404) + { + } + else if (response.statusCode == 405) + { + } + // + // Assume standard error response with errorCode and errorMessage + // + else + { + if (msg['errorCode'] !== undefined) { + response.body.errorCode = msg['errorCode']; + } + + if (msg['errorMessage'] !== undefined) { + response.body.errorMessage = msg['errorMessage']; + } + } + } + + responseHandler(response); + }; + + + this.context.request( + 'GET', + path, + body, + undefined, + handleResponse + ); + } + get( accountID, queryParams, @@ -465,7 +511,7 @@ class EntitySpec { if (response.statusCode == 200) { if (msg['prices'] !== undefined) { - response.body.prices = msg['prices'].map(x => new Price(x)); + response.body.prices = msg['prices'].map(x => new ClientPrice(x)); } if (msg['homeConversions'] !== undefined) { @@ -560,7 +606,7 @@ class EntitySpec { if (response.statusCode == 200) { if (msg['price'] !== undefined) { - response.body.price = new Price(msg['price']); + response.body.price = new ClientPrice(msg['price']); } if (msg['heartbeat'] !== undefined) { @@ -623,15 +669,130 @@ class EntitySpec { ); } + candles( + instrument, + queryParams, + responseHandler + ) + { + if (!responseHandler) + { + throw "No responseHandler provided for API call" + } + + + let path = '/v3/accounts/{accountID}/instruments/{instrument}/candles'; + + queryParams = queryParams || {}; + + path = path.replace('{' + 'instrument' + '}', instrument); + + path = path + "?"; + if (typeof queryParams['price'] !== 'undefined') { + path = path + "price=" + queryParams['price'] + "&"; + } + if (typeof queryParams['granularity'] !== 'undefined') { + path = path + "granularity=" + queryParams['granularity'] + "&"; + } + if (typeof queryParams['count'] !== 'undefined') { + path = path + "count=" + queryParams['count'] + "&"; + } + if (typeof queryParams['from'] !== 'undefined') { + path = path + "from=" + queryParams['from'] + "&"; + } + if (typeof queryParams['to'] !== 'undefined') { + path = path + "to=" + queryParams['to'] + "&"; + } + if (typeof queryParams['smooth'] !== 'undefined') { + path = path + "smooth=" + queryParams['smooth'] + "&"; + } + if (typeof queryParams['includeFirst'] !== 'undefined') { + path = path + "includeFirst=" + queryParams['includeFirst'] + "&"; + } + if (typeof queryParams['dailyAlignment'] !== 'undefined') { + path = path + "dailyAlignment=" + queryParams['dailyAlignment'] + "&"; + } + if (typeof queryParams['alignmentTimezone'] !== 'undefined') { + path = path + "alignmentTimezone=" + queryParams['alignmentTimezone'] + "&"; + } + if (typeof queryParams['weeklyAlignment'] !== 'undefined') { + path = path + "weeklyAlignment=" + queryParams['weeklyAlignment'] + "&"; + } + if (typeof queryParams['units'] !== 'undefined') { + path = path + "units=" + queryParams['units'] + "&"; + } + + let body = {}; + + let handleResponse = (response) => { + if (response.contentType.startsWith("application/json")) + { + let msg = JSON.parse(response.rawBody); + + response.body = {}; + + if (response.statusCode == 200) + { + if (msg['instrument'] !== undefined) { + response.body.instrument = msg['instrument']; + } + + if (msg['granularity'] !== undefined) { + response.body.granularity = msg['granularity']; + } + + if (msg['candles'] !== undefined) { + response.body.candles = msg['candles'].map(x => new instrument.Candlestick(x)); + } + + } + else if (response.statusCode == 400) + { + } + else if (response.statusCode == 401) + { + } + else if (response.statusCode == 404) + { + } + else if (response.statusCode == 405) + { + } + // + // Assume standard error response with errorCode and errorMessage + // + else + { + if (msg['errorCode'] !== undefined) { + response.body.errorCode = msg['errorCode']; + } + + if (msg['errorMessage'] !== undefined) { + response.body.errorMessage = msg['errorMessage']; + } + } + } + + responseHandler(response); + }; + + + this.context.request( + 'GET', + path, + body, + undefined, + handleResponse + ); + } + } -exports.Price = Price; -exports.PriceBucket = PriceBucket; +exports.ClientPrice = ClientPrice; exports.QuoteHomeConversionFactors = QuoteHomeConversionFactors; exports.HomeConversions = HomeConversions; -exports.ClientPrice = ClientPrice; exports.PricingHeartbeat = PricingHeartbeat; exports.EntitySpec = EntitySpec; diff --git a/src/pricing_common.js b/src/pricing_common.js new file mode 100644 index 0000000..e1c6c11 --- /dev/null +++ b/src/pricing_common.js @@ -0,0 +1,183 @@ +/* jshint esversion: 6 */ + +"use strict"; + +var Definition = require('./base').Definition; +var Property = require('./base').Property; +var Field = require('./base').Field; + + + + +const PriceBucket_Properties = [ + new Property( + 'price', + "Price", + "The Price offered by the PriceBucket", + 'primitive', + 'pricing_common.PriceValue' + ), + new Property( + 'liquidity', + "Liquidity", + "The amount of liquidity offered by the PriceBucket", + 'primitive', + 'integer' + ), +]; + +class PriceBucket extends Definition { + constructor(data) { + super(); + + this._summaryFormat = ""; + + this._nameFormat = ""; + + this._properties = PriceBucket_Properties; + + data = data || {}; + + if (data['price'] !== undefined) { + this.price = data['price']; + } + + if (data['liquidity'] !== undefined) { + this.liquidity = data['liquidity']; + } + + } +} + +const Price_Properties = [ + new Property( + 'instrument', + "Instrument", + "The Price's Instrument.", + 'primitive', + 'primitives.InstrumentName' + ), + new Property( + 'tradeable', + "Is Tradeable", + "Flag indicating if the Price is tradeable or not", + 'primitive', + 'boolean' + ), + new Property( + 'timestamp', + "Timestamp", + "The date/time when the Price was created.", + 'primitive', + 'primitives.DateTime' + ), + new Property( + 'baseBid', + "Base Bid", + "The base bid price as calculated by pricing.", + 'primitive', + 'pricing_common.PriceValue' + ), + new Property( + 'baseAsk', + "Base Ask", + "The base ask price as calculated by pricing.", + 'primitive', + 'pricing_common.PriceValue' + ), + new Property( + 'bids', + "Bids", + "The list of prices and liquidity available on the Instrument's bid side. It is possible for this list to be empty if there is no bid liquidity currently available for the Instrument in the Account.", + 'array_object', + 'PriceBucket' + ), + new Property( + 'asks', + "Asks", + "The list of prices and liquidity available on the Instrument's ask side. It is possible for this list to be empty if there is no ask liquidity currently available for the Instrument in the Account.", + 'array_object', + 'PriceBucket' + ), + new Property( + 'closeoutBid', + "Closeout Bid", + "The closeout bid price. This price is used when a bid is required to closeout a Position (margin closeout or manual) yet there is no bid liquidity. The closeout bid is never used to open a new position.", + 'primitive', + 'pricing_common.PriceValue' + ), + new Property( + 'closeoutAsk', + "Closeout Ask", + "The closeout ask price. This price is used when an ask is required to closeout a Position (margin closeout or manual) yet there is no ask liquidity. The closeout ask is never used to open a new position.", + 'primitive', + 'pricing_common.PriceValue' + ), +]; + +class Price extends Definition { + constructor(data) { + super(); + + this._summaryFormat = ""; + + this._nameFormat = ""; + + this._properties = Price_Properties; + + data = data || {}; + + if (data['instrument'] !== undefined) { + this.instrument = data['instrument']; + } + + if (data['tradeable'] !== undefined) { + this.tradeable = data['tradeable']; + } + + if (data['timestamp'] !== undefined) { + this.timestamp = data['timestamp']; + } + + if (data['baseBid'] !== undefined) { + this.baseBid = data['baseBid']; + } + + if (data['baseAsk'] !== undefined) { + this.baseAsk = data['baseAsk']; + } + + if (data['bids'] !== undefined) { + this.bids = data['bids'].map(x => new PriceBucket(x)); + } + + if (data['asks'] !== undefined) { + this.asks = data['asks'].map(x => new PriceBucket(x)); + } + + if (data['closeoutBid'] !== undefined) { + this.closeoutBid = data['closeoutBid']; + } + + if (data['closeoutAsk'] !== undefined) { + this.closeoutAsk = data['closeoutAsk']; + } + + } +} + +class EntitySpec { + constructor(context) { + this.context = context; + this.PriceBucket = PriceBucket; + this.Price = Price; + } + + + +} + +exports.PriceBucket = PriceBucket; +exports.Price = Price; + +exports.EntitySpec = EntitySpec; diff --git a/src/trade.js b/src/trade.js index 185fb8d..e955304 100644 --- a/src/trade.js +++ b/src/trade.js @@ -31,7 +31,7 @@ const Trade_Properties = [ "Fill Price", "The execution price of the Trade.", 'primitive', - 'pricing.PriceValue' + 'pricing_common.PriceValue' ), new Property( 'openTime', @@ -94,7 +94,7 @@ const Trade_Properties = [ "Average Close Price", "The average closing price of the Trade. Only present if the Trade has been closed or reduced at least once.", 'primitive', - 'pricing.PriceValue' + 'pricing_common.PriceValue' ), new Property( 'closingTransactionIDs', @@ -258,7 +258,7 @@ const TradeSummary_Properties = [ "Fill Price", "The execution price of the Trade.", 'primitive', - 'pricing.PriceValue' + 'pricing_common.PriceValue' ), new Property( 'openTime', @@ -321,7 +321,7 @@ const TradeSummary_Properties = [ "Average Close Price", "The average closing price of the Trade. Only present if the Trade has been closed or reduced at least once.", 'primitive', - 'pricing.PriceValue' + 'pricing_common.PriceValue' ), new Property( 'closingTransactionIDs', diff --git a/src/transaction.js b/src/transaction.js index 51aa6a1..d39f1e4 100644 --- a/src/transaction.js +++ b/src/transaction.js @@ -98,6 +98,10 @@ class Transaction extends Definition { { return new Transaction(transaction); } + else if (transaction["type"] == "MARKET_ORDER") + { + return new MarketOrderTransaction(transaction); + } else if (transaction["type"] == "ORDER_FILL") { return new OrderFillTransaction(transaction); @@ -106,29 +110,45 @@ class Transaction extends Definition { { return new OrderCancelTransaction(transaction); } - else if (transaction["type"] == "ORDER_CANCEL_REJECT") + else if (transaction["type"] == "MARKET_ORDER_REJECT") { - return new OrderCancelRejectTransaction(transaction); + return new MarketOrderRejectTransaction(transaction); } - else if (transaction["type"] == "ORDER_CLIENT_EXTENSIONS_MODIFY") + else if (transaction["type"] == "TRADE_CLIENT_EXTENSIONS_MODIFY") { - return new OrderClientExtensionsModifyTransaction(transaction); + return new TradeClientExtensionsModifyTransaction(transaction); } - else if (transaction["type"] == "ORDER_CLIENT_EXTENSIONS_MODIFY_REJECT") + else if (transaction["type"] == "TRADE_CLIENT_EXTENSIONS_MODIFY_REJECT") { - return new OrderClientExtensionsModifyRejectTransaction(transaction); + return new TradeClientExtensionsModifyRejectTransaction(transaction); } - else if (transaction["type"] == "CREATE") + else if (transaction["type"] == "TAKE_PROFIT_ORDER") { - return new CreateTransaction(transaction); + return new TakeProfitOrderTransaction(transaction); } - else if (transaction["type"] == "CLOSE") + else if (transaction["type"] == "STOP_LOSS_ORDER") { - return new CloseTransaction(transaction); + return new StopLossOrderTransaction(transaction); } - else if (transaction["type"] == "REOPEN") + else if (transaction["type"] == "TRAILING_STOP_LOSS_ORDER") { - return new ReopenTransaction(transaction); + return new TrailingStopLossOrderTransaction(transaction); + } + else if (transaction["type"] == "ORDER_CANCEL_REJECT") + { + return new OrderCancelRejectTransaction(transaction); + } + else if (transaction["type"] == "TAKE_PROFIT_ORDER_REJECT") + { + return new TakeProfitOrderRejectTransaction(transaction); + } + else if (transaction["type"] == "STOP_LOSS_ORDER_REJECT") + { + return new StopLossOrderRejectTransaction(transaction); + } + else if (transaction["type"] == "TRAILING_STOP_LOSS_ORDER_REJECT") + { + return new TrailingStopLossOrderRejectTransaction(transaction); } else if (transaction["type"] == "CLIENT_CONFIGURE") { @@ -138,21 +158,25 @@ class Transaction extends Definition { { return new ClientConfigureRejectTransaction(transaction); } - else if (transaction["type"] == "TRANSFER_FUNDS") + else if (transaction["type"] == "CREATE") { - return new TransferFundsTransaction(transaction); + return new CreateTransaction(transaction); } - else if (transaction["type"] == "TRANSFER_FUNDS_REJECT") + else if (transaction["type"] == "CLOSE") { - return new TransferFundsRejectTransaction(transaction); + return new CloseTransaction(transaction); } - else if (transaction["type"] == "MARKET_ORDER") + else if (transaction["type"] == "REOPEN") { - return new MarketOrderTransaction(transaction); + return new ReopenTransaction(transaction); } - else if (transaction["type"] == "MARKET_ORDER_REJECT") + else if (transaction["type"] == "TRANSFER_FUNDS") { - return new MarketOrderRejectTransaction(transaction); + return new TransferFundsTransaction(transaction); + } + else if (transaction["type"] == "TRANSFER_FUNDS_REJECT") + { + return new TransferFundsRejectTransaction(transaction); } else if (transaction["type"] == "FIXED_PRICE_ORDER") { @@ -182,37 +206,13 @@ class Transaction extends Definition { { return new MarketIfTouchedOrderRejectTransaction(transaction); } - else if (transaction["type"] == "TAKE_PROFIT_ORDER") - { - return new TakeProfitOrderTransaction(transaction); - } - else if (transaction["type"] == "TAKE_PROFIT_ORDER_REJECT") - { - return new TakeProfitOrderRejectTransaction(transaction); - } - else if (transaction["type"] == "STOP_LOSS_ORDER") - { - return new StopLossOrderTransaction(transaction); - } - else if (transaction["type"] == "STOP_LOSS_ORDER_REJECT") - { - return new StopLossOrderRejectTransaction(transaction); - } - else if (transaction["type"] == "TRAILING_STOP_LOSS_ORDER") - { - return new TrailingStopLossOrderTransaction(transaction); - } - else if (transaction["type"] == "TRAILING_STOP_LOSS_ORDER_REJECT") - { - return new TrailingStopLossOrderRejectTransaction(transaction); - } - else if (transaction["type"] == "TRADE_CLIENT_EXTENSIONS_MODIFY") + else if (transaction["type"] == "ORDER_CLIENT_EXTENSIONS_MODIFY") { - return new TradeClientExtensionsModifyTransaction(transaction); + return new OrderClientExtensionsModifyTransaction(transaction); } - else if (transaction["type"] == "TRADE_CLIENT_EXTENSIONS_MODIFY_REJECT") + else if (transaction["type"] == "ORDER_CLIENT_EXTENSIONS_MODIFY_REJECT") { - return new TradeClientExtensionsModifyRejectTransaction(transaction); + return new OrderClientExtensionsModifyRejectTransaction(transaction); } else if (transaction["type"] == "MARGIN_CALL_ENTER") { @@ -1203,7 +1203,7 @@ const MarketOrderTransaction_Properties = [ "Price Bound", "The worst price that the client is willing to have the Market Order filled at.", 'primitive', - 'pricing.PriceValue' + 'pricing_common.PriceValue' ), new Property( 'positionFill', @@ -1483,7 +1483,7 @@ const MarketOrderRejectTransaction_Properties = [ "Price Bound", "The worst price that the client is willing to have the Market Order filled at.", 'primitive', - 'pricing.PriceValue' + 'pricing_common.PriceValue' ), new Property( 'positionFill', @@ -1767,7 +1767,7 @@ const FixedPriceOrderTransaction_Properties = [ "Price", "The price specified for the Fixed Price Order. This price is the exact price that the Fixed Price Order will be filled at.", 'primitive', - 'pricing.PriceValue' + 'pricing_common.PriceValue' ), new Property( 'positionFill', @@ -1989,7 +1989,7 @@ const LimitOrderTransaction_Properties = [ "Price", "The price threshold specified for the Limit Order. The Limit Order will only be filled by a market price that is equal to or better than this price.", 'primitive', - 'pricing.PriceValue' + 'pricing_common.PriceValue' ), new Property( 'timeInForce', @@ -2261,7 +2261,7 @@ const LimitOrderRejectTransaction_Properties = [ "Price", "The price threshold specified for the Limit Order. The Limit Order will only be filled by a market price that is equal to or better than this price.", 'primitive', - 'pricing.PriceValue' + 'pricing_common.PriceValue' ), new Property( 'timeInForce', @@ -2533,14 +2533,14 @@ const StopOrderTransaction_Properties = [ "Price", "The price threshold specified for the Stop Order. The Stop Order will only be filled by a market price that is equal to or worse than this price.", 'primitive', - 'pricing.PriceValue' + 'pricing_common.PriceValue' ), new Property( 'priceBound', "Price Bound", "The worst market price that may be used to fill this Stop Order. If the market gaps and crosses through both the price and the priceBound, the Stop Order will be cancelled instead of being filled.", 'primitive', - 'pricing.PriceValue' + 'pricing_common.PriceValue' ), new Property( 'timeInForce', @@ -2816,14 +2816,14 @@ const StopOrderRejectTransaction_Properties = [ "Price", "The price threshold specified for the Stop Order. The Stop Order will only be filled by a market price that is equal to or worse than this price.", 'primitive', - 'pricing.PriceValue' + 'pricing_common.PriceValue' ), new Property( 'priceBound', "Price Bound", "The worst market price that may be used to fill this Stop Order. If the market gaps and crosses through both the price and the priceBound, the Stop Order will be cancelled instead of being filled.", 'primitive', - 'pricing.PriceValue' + 'pricing_common.PriceValue' ), new Property( 'timeInForce', @@ -3099,14 +3099,14 @@ const MarketIfTouchedOrderTransaction_Properties = [ "Price", "The price threshold specified for the MarketIfTouched Order. The MarketIfTouched Order will only be filled by a market price that crosses this price from the direction of the market price at the time when the Order was created (the initialMarketPrice). Depending on the value of the Order's price and initialMarketPrice, the MarketIfTouchedOrder will behave like a Limit or a Stop Order.", 'primitive', - 'pricing.PriceValue' + 'pricing_common.PriceValue' ), new Property( 'priceBound', "Price Value", "The worst market price that may be used to fill this MarketIfTouched Order.", 'primitive', - 'pricing.PriceValue' + 'pricing_common.PriceValue' ), new Property( 'timeInForce', @@ -3382,14 +3382,14 @@ const MarketIfTouchedOrderRejectTransaction_Properties = [ "Price", "The price threshold specified for the MarketIfTouched Order. The MarketIfTouched Order will only be filled by a market price that crosses this price from the direction of the market price at the time when the Order was created (the initialMarketPrice). Depending on the value of the Order's price and initialMarketPrice, the MarketIfTouchedOrder will behave like a Limit or a Stop Order.", 'primitive', - 'pricing.PriceValue' + 'pricing_common.PriceValue' ), new Property( 'priceBound', "Price Value", "The worst market price that may be used to fill this MarketIfTouched Order.", 'primitive', - 'pricing.PriceValue' + 'pricing_common.PriceValue' ), new Property( 'timeInForce', @@ -3665,7 +3665,7 @@ const TakeProfitOrderTransaction_Properties = [ "Price", "The price threshold specified for the TakeProfit Order. The associated Trade will be closed by a market price that is equal to or better than this threshold.", 'primitive', - 'pricing.PriceValue' + 'pricing_common.PriceValue' ), new Property( 'timeInForce', @@ -3890,7 +3890,7 @@ const TakeProfitOrderRejectTransaction_Properties = [ "Price", "The price threshold specified for the TakeProfit Order. The associated Trade will be closed by a market price that is equal to or better than this threshold.", 'primitive', - 'pricing.PriceValue' + 'pricing_common.PriceValue' ), new Property( 'timeInForce', @@ -4115,7 +4115,7 @@ const StopLossOrderTransaction_Properties = [ "Price", "The price threshold specified for the Stop Loss Order. If the guaranteed flag is false, the associated Trade will be closed by a market price that is equal to or worse than this threshold. If the flag is true the associated Trade will be closed at this price.", 'primitive', - 'pricing.PriceValue' + 'pricing_common.PriceValue' ), new Property( 'distance', @@ -4373,7 +4373,7 @@ const StopLossOrderRejectTransaction_Properties = [ "Price", "The price threshold specified for the Stop Loss Order. If the guaranteed flag is false, the associated Trade will be closed by a market price that is equal to or worse than this threshold. If the flag is true the associated Trade will be closed at this price.", 'primitive', - 'pricing.PriceValue' + 'pricing_common.PriceValue' ), new Property( 'distance', @@ -5075,7 +5075,7 @@ const OrderFillTransaction_Properties = [ new Property( 'units', "Fill Units", - "The number of units filled by the Order.", + "The number of units filled by the OrderFill.", 'primitive', 'primitives.DecimalNumber' ), @@ -5098,7 +5098,14 @@ const OrderFillTransaction_Properties = [ "Fill Price", "This field is now deprecated and should no longer be used. The individual tradesClosed, tradeReduced and tradeOpened fields contain the exact/official price each unit was filled at.", 'primitive', - 'pricing.PriceValue' + 'pricing_common.PriceValue' + ), + new Property( + 'fullVWAP', + "Full VWAP", + "The price that all of the units of the OrderFill should have been filled at, in the absence of guaranteed price execution. This factors in the Account's current ClientPrice, used liquidity and the units of the OrderFill only. If no Trades were closed with their price clamped for guaranteed stop loss enforcement, then this value will match the price fields of each Trade opened, closed, and reduced, and they will all be the exact same.", + 'primitive', + 'pricing_common.PriceValue' ), new Property( 'fullPrice', @@ -5250,6 +5257,10 @@ class OrderFillTransaction extends Definition { this.price = data['price']; } + if (data['fullVWAP'] !== undefined) { + this.fullVWAP = data['fullVWAP']; + } + if (data['fullPrice'] !== undefined) { this.fullPrice = new pricing.ClientPrice(data['fullPrice']); } @@ -6860,7 +6871,7 @@ const TakeProfitDetails_Properties = [ "Price", "The price that the Take Profit Order will be triggered at. Only one of the price and distance fields may be specified.", 'primitive', - 'pricing.PriceValue' + 'pricing_common.PriceValue' ), new Property( 'timeInForce', @@ -6925,7 +6936,7 @@ const StopLossDetails_Properties = [ "Price", "The price that the Stop Loss Order will be triggered at. Only one of the price and distance fields may be specified.", 'primitive', - 'pricing.PriceValue' + 'pricing_common.PriceValue' ), new Property( 'distance', @@ -7091,7 +7102,7 @@ const TradeOpen_Properties = [ "Units Opened Price", "The average price that the units were opened at.", 'primitive', - 'pricing.PriceValue' + 'pricing_common.PriceValue' ), new Property( 'guaranteedExecutionFee', @@ -7186,7 +7197,7 @@ const TradeReduce_Properties = [ "Units Closed Price", "The average price that the units were closed at. This price may be clamped for guaranteed Stop Loss Orders.", 'primitive', - 'pricing.PriceValue' + 'pricing_common.PriceValue' ), new Property( 'realizedPL', diff --git a/v20-3.0.25.tar.gz b/v20-3.0.25.tar.gz new file mode 100644 index 0000000..08e65a6 Binary files /dev/null and b/v20-3.0.25.tar.gz differ