├── LICENSE ├── README.md ├── src ├── ChangeLog ├── README.md ├── account.js ├── base.js ├── context.js ├── instrument.js ├── order.js ├── package.json ├── position.js ├── pricing.js ├── pricing_common.js ├── primitives.js ├── site.js ├── trade.js ├── transaction.js └── user.js ├── v20-3.0.1.tar.gz ├── v20-3.0.10.tar.gz ├── v20-3.0.11.tar.gz ├── v20-3.0.13.tar.gz ├── v20-3.0.14.tar.gz ├── v20-3.0.15.tar.gz ├── v20-3.0.16.tar.gz ├── v20-3.0.18.tar.gz ├── v20-3.0.2.tar.gz ├── v20-3.0.22.tar.gz ├── v20-3.0.25.tar.gz ├── v20-3.0.3.tar.gz ├── v20-3.0.4.tar.gz ├── v20-3.0.5.tar.gz ├── v20-3.0.6.tar.gz ├── v20-3.0.7.tar.gz ├── v20-3.0.8.tar.gz └── v20-3.0.9.tar.gz /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 OANDA 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | src/README.md -------------------------------------------------------------------------------- /src/ChangeLog: -------------------------------------------------------------------------------- 1 | OANDA v20 API Change Log 2 | 3 | Version 3.0.25 (September 28, 2018) 4 | 5 | * All - Added orderBook and PositionBook endpoints. Issue#29 6 | (https://github.com/oanda/v20-python/issues/29) 7 | 8 | 9 | Version 3.0.24 (May 11, 2018) 10 | 11 | * Java - Added support for Accept-Datetime-Format and additional 12 | custom headers. Issue#8 (https://github.com/oanda/v20-java/issues/8) 13 | 14 | 15 | Version 3.0.23 (May 04, 2018) 16 | 17 | * Java - Fixed using null in a TradeSetDependentOrdersRequest Issue#7 18 | (https://github.com/oanda/v20-java/issues/7) 19 | 20 | 21 | Version 3.0.22 (April 11, 2018) 22 | 23 | * Various documentation and example improvements 24 | 25 | * Added Guaranteed Stop Loss Order support 26 | 27 | 28 | Version 3.0.21 (November 08, 2017) 29 | 30 | * Include error code and error message in request exceptions (Java) 31 | 32 | * Improved README.md (Java) 33 | 34 | 35 | Version 3.0.20 (September 26, 2017) 36 | 37 | * Added toString() methods to Java classes 38 | 39 | 40 | Version 3.0.19 (September 12, 2017) 41 | 42 | * Corrected encoding of CSV query parameters in Java 43 | 44 | 45 | Version 3.0.18 (May 12, 2017) 46 | 47 | * Corrected handling of Collections in Java implementation 48 | 49 | * Published commission related fields 50 | 51 | 52 | Version 3.0.17 (April 21, 2017) 53 | 54 | * Initial Java implementation 55 | 56 | 57 | Version 3.0.16 (April 04, 2017) 58 | 59 | * Added streaming support for v20 Javascript wrapper 60 | 61 | 62 | Version 3.0.15 (March 28, 2017) 63 | 64 | * Various bug fixes 65 | 66 | 67 | Version 3.0.14 (Unreleased) 68 | 69 | * Changed v20-python entity __str__ representation to use yaml 70 | 71 | 72 | Version 3.0.13 (December 08, 2016) 73 | 74 | * Fixed v20-python string-to-float regression 75 | 76 | * First OpenAPI specification release 77 | 78 | 79 | Version 3.0.12 (Unreleased) 80 | 81 | * v20-python fixed bug when parsing an Instrument from 82 | ctx.acccount.instruments() request 83 | 84 | * v20-python intercept requests.exceptions.ChunkedEncodingError when 85 | a stream is interrupted 86 | 87 | * prepping for first openapi specification release 88 | 89 | 90 | Version 3.0.11 (Unreleased) 91 | 92 | * stop using custom Boolean definition 93 | 94 | * publish Header specifications for responses 95 | 96 | * fixed the MarginCallExtenTransaction description 97 | 98 | * added missing ORDER_CANCEL_REJECT to appropriate enums 99 | 100 | * fixed some candlestick documentation 101 | 102 | * added delayed trade closure transaction type 103 | 104 | * added response Headers to documentation 105 | 106 | 107 | Version 3.0.10 (Unreleased) 108 | 109 | * v20-python accepts floats for numeric values, and will convert them 110 | to their string representation before sending them over the wire 111 | 112 | * v20-python automatically decodes string-encoded floats into native 113 | python floats. This behaviour can be disabled/enabled through the 114 | Context 115 | 116 | * v20-python Context initialiser sets default values port=443, 117 | ssl=True 118 | 119 | * v20-python Context initialiser allows configuration of token, 120 | string to float conversion, stream_chunk_size, stream_timeout, 121 | datetime_format and poll_timeout 122 | 123 | * v20-python poll_timeout default changed from 10 to 2 124 | 125 | 126 | Version 3.0.9 (Unreleased) 127 | 128 | * v20-python uses ujson instead of json for improved performance 129 | 130 | * v20-python wrapped some requests exceptions with v20 exceptions 131 | 132 | * v20-python library change v20 class definitions to explicitly 133 | declare properties (with comments) instead of using the property 134 | metadata attached to each class 135 | 136 | * v20-python library isolate property metadata in a single file 137 | 138 | * v20-python object instantiation from dict simplified and cleaned up 139 | 140 | * more v20-python library documentation 141 | 142 | 143 | Version 3.0.8 (Unreleased) 144 | 145 | * v20-python supports setting timeouts for polling and streaming 146 | requests 147 | 148 | 149 | Version 3.0.7 (Unreleased) 150 | 151 | * Stream chunk size if now configurable in each context and defaults 152 | to 512 bytes 153 | 154 | 155 | Version 3.0.6 (Unreleased) 156 | 157 | * Added time format support to v20 python bindings 158 | 159 | * Extended Transaction filtering to support Transaction Types 160 | 161 | * Factored all common HTTP error responses out of API 162 | 163 | 164 | Version 3.0.5 (Unreleased) 165 | 166 | * Added v20 python aliases for creation and replacement of orders 167 | 168 | 169 | Version 3.0.4 (Unreleased) 170 | 171 | * Added instrument endpoints with support for Candles. 172 | 173 | 174 | Version 3.0.3 (Unreleased) 175 | 176 | * Added support for Pricing and Transaction streaming endpoints. 177 | 178 | * Deprecated "includeUnitsAvailable" for REST pricing endpoint. 179 | 180 | * Deprecated "quoteHomeConversionFactors" and "unitsAvailable" for 181 | the Price object. 182 | 183 | 184 | Version 3.0.2 (Unreleased) 185 | 186 | * Added support for Python 3.5 187 | 188 | 189 | Version 3.0.1 (Unreleased) 190 | 191 | * Added TransactRejectReason enum 192 | 193 | 194 | Version 3.0.0 (Unreleased) 195 | 196 | * Initial Release 197 | 198 | 199 | 200 | -------------------------------------------------------------------------------- /src/README.md: -------------------------------------------------------------------------------- 1 | The OANDA v20 REST API provides programmatic access to OANDA's next generation 2 | v20 trading engine. 3 | 4 | ## Installation 5 | 6 | If you have the node package manager, npm, installed: 7 | 8 | ```shell 9 | npm install -g @oanda/v20 10 | ``` 11 | 12 | Leave off the `-g` if you don't wish to install globally. If you don't wish to use npm: 13 | 14 | ``` 15 | git clone https://github.com/oanda/v20-javascript.git 16 | ``` 17 | 18 | ## Documentation 19 | 20 | For documentation, usage and examples, see: http://developer.oanda.com/rest-live-v20/introduction 21 | -------------------------------------------------------------------------------- /src/base.js: -------------------------------------------------------------------------------- 1 | /* jshint esversion: 6 */ 2 | 3 | "use strict"; 4 | 5 | class Property { 6 | constructor(name, displayName, description, typeClass, typeName) { 7 | this.name = name; 8 | this.displayName = displayName; 9 | this.description = description; 10 | this.typeClass = typeClass; 11 | this.typeName = typeName; 12 | } 13 | } 14 | 15 | class Field extends Property{ 16 | constructor(property, value) { 17 | super( 18 | property.name, 19 | property.displayName, 20 | property.description, 21 | property.typeClass, 22 | property.typeName 23 | ); 24 | this.value = value; 25 | } 26 | } 27 | 28 | class Definition { 29 | constructor() { 30 | this._summaryFormat = ""; 31 | this._nameFormat = ""; 32 | this._properties = []; 33 | } 34 | 35 | toJSON(key) { 36 | let repr = {}; 37 | 38 | for (let val in this) 39 | { 40 | if (val == "_properties") { continue; } 41 | if (val == "_summaryFormat") { continue; } 42 | if (val == "_nameFormat") { continue; } 43 | repr[val] = this[val]; 44 | } 45 | 46 | return repr; 47 | } 48 | 49 | name() { 50 | let nameStr = this._nameFormat; 51 | 52 | let re = /{([^}]+)}/g; 53 | 54 | let matches = nameStr.match(re); 55 | 56 | for (let match of matches || []) 57 | { 58 | let key = match.slice(1, -1); 59 | 60 | let value = this[key] || match; 61 | 62 | nameStr = nameStr.replace(match, value); 63 | } 64 | 65 | return nameStr; 66 | } 67 | 68 | summary() { 69 | let summaryStr = this._summaryFormat; 70 | 71 | let re = /{([^}]+)}/g; 72 | 73 | let matches = summaryStr.match(re); 74 | 75 | for (let match of matches || []) 76 | { 77 | let key = match.slice(1, -1); 78 | 79 | let value = this[key] || match; 80 | 81 | summaryStr = summaryStr.replace(match, value); 82 | } 83 | 84 | return summaryStr; 85 | } 86 | 87 | title() { 88 | let nameStr = this.name(); 89 | let summaryStr = this.summary(); 90 | 91 | let titleStr = nameStr; 92 | 93 | if (nameStr.length > 0 && summaryStr.length > 0) 94 | { 95 | titleStr += ": "; 96 | } 97 | 98 | titleStr += summaryStr; 99 | 100 | return titleStr; 101 | } 102 | 103 | toString() { 104 | let s = this.title(); 105 | 106 | this._properties.forEach(prop => { 107 | let value = this[prop.name]; 108 | 109 | if (value === undefined) { return; } 110 | 111 | s += "\n" + prop.displayName + ": "; 112 | 113 | if (value instanceof Array) 114 | { 115 | s += "[" + value.length + "]"; 116 | } 117 | else 118 | { 119 | s += value; 120 | } 121 | }); 122 | 123 | return s; 124 | } 125 | 126 | fields() { 127 | let ret = []; 128 | 129 | this._properties.forEach(prop => { 130 | let value = this[prop.name]; 131 | 132 | if (typeof value != 'undefined') 133 | { 134 | ret.push(new Field(prop, value)); 135 | } 136 | }); 137 | 138 | return ret; 139 | } 140 | } 141 | 142 | exports.Definition = Definition; 143 | exports.Property = Property; 144 | exports.Field = Field; 145 | -------------------------------------------------------------------------------- /src/context.js: -------------------------------------------------------------------------------- 1 | /* jshint esversion: 6 */ 2 | 3 | "use strict"; 4 | 5 | var account = require("./account"); 6 | var user = require("./user"); 7 | var position = require("./position"); 8 | var pricing = require("./pricing"); 9 | var transaction = require("./transaction"); 10 | var primitives = require("./primitives"); 11 | var trade = require("./trade"); 12 | var site = require("./site"); 13 | var pricing_common = require("./pricing_common"); 14 | var order = require("./order"); 15 | var instrument = require("./instrument"); 16 | 17 | 18 | class Response { 19 | constructor( 20 | method, 21 | path, 22 | statusCode, 23 | statusMessage, 24 | contentType, 25 | rawBody 26 | ) { 27 | this.method = method; 28 | this.path = path; 29 | this.statusCode = statusCode.toString(); 30 | this.statusMessage = statusMessage; 31 | this.contentType = contentType; 32 | this.rawBody = rawBody; 33 | this.body = null; 34 | } 35 | 36 | isSuccess() { 37 | return this.statusCode.startsWith("2"); 38 | } 39 | 40 | isRedirection() { 41 | return this.statusCode.startsWith("3"); 42 | } 43 | 44 | isClientError() { 45 | return this.statusCode.startsWith("4"); 46 | } 47 | 48 | isServerError() { 49 | return this.statusCode.startsWith("5"); 50 | } 51 | 52 | isError() { 53 | return ( 54 | this.isClientError() || this.isServerError() 55 | ); 56 | } 57 | } 58 | 59 | class Context { 60 | constructor(hostname, port, ssl, application) { 61 | application = application || ""; 62 | 63 | this.username = ""; 64 | 65 | this.hostname = hostname; 66 | 67 | this.port = port; 68 | 69 | this.headers = { 70 | "Content-Type": "application/json", 71 | "OANDA-Agent" : `v20-javascript/3.0.25 (${application})` 72 | }; 73 | 74 | this.token = ""; 75 | 76 | if (ssl) 77 | { 78 | this.http = require('https'); 79 | } 80 | else 81 | { 82 | this.http = require('http'); 83 | } 84 | 85 | this.account = new account.EntitySpec(this); 86 | this.user = new user.EntitySpec(this); 87 | this.position = new position.EntitySpec(this); 88 | this.pricing = new pricing.EntitySpec(this); 89 | this.transaction = new transaction.EntitySpec(this); 90 | this.primitives = new primitives.EntitySpec(this); 91 | this.trade = new trade.EntitySpec(this); 92 | this.site = new site.EntitySpec(this); 93 | this.pricing_common = new pricing_common.EntitySpec(this); 94 | this.order = new order.EntitySpec(this); 95 | this.instrument = new instrument.EntitySpec(this); 96 | } 97 | 98 | setToken(token) { 99 | this.token = token; 100 | this.headers['Authorization'] = "Bearer " + this.token; 101 | } 102 | 103 | request(method, path, body, streamChunkHandler, responseHandler) { 104 | let headers = JSON.parse(JSON.stringify(this.headers)); 105 | 106 | let postData = ""; 107 | 108 | if (Object.keys(body).length > 0) 109 | { 110 | postData = JSON.stringify(body); 111 | headers['Content-Length'] = postData.length; 112 | } 113 | 114 | let options = { 115 | hostname: this.hostname, 116 | port: this.port, 117 | method: method, 118 | path: path, 119 | headers: headers 120 | }; 121 | 122 | let req = this.http.request( 123 | options, 124 | response => { 125 | let responseBody = ''; 126 | 127 | response.on('data', d => { 128 | responseBody += d; 129 | 130 | if (streamChunkHandler) 131 | { 132 | let chunks = responseBody.split("\n"); 133 | 134 | chunks.forEach(chunk => { 135 | if (chunk.length > 0) 136 | { 137 | streamChunkHandler(chunk); 138 | } 139 | 140 | responseBody = chunk; 141 | }); 142 | } 143 | }); 144 | 145 | response.on('end', () => { 146 | if (responseHandler) 147 | { 148 | responseHandler( 149 | new Response( 150 | method, 151 | path, 152 | response.statusCode, 153 | response.statusMessage, 154 | response.headers['content-type'], 155 | responseBody 156 | ) 157 | ); 158 | } 159 | }); 160 | } 161 | ); 162 | 163 | if (postData.length > 0) 164 | { 165 | req.write(postData); 166 | } 167 | 168 | req.end(); 169 | } 170 | } 171 | 172 | exports.Context = Context; 173 | -------------------------------------------------------------------------------- /src/instrument.js: -------------------------------------------------------------------------------- 1 | /* jshint esversion: 6 */ 2 | 3 | "use strict"; 4 | 5 | var Definition = require('./base').Definition; 6 | var Property = require('./base').Property; 7 | var Field = require('./base').Field; 8 | 9 | var pricing_common = require('./pricing_common'); 10 | 11 | 12 | 13 | const Candlestick_Properties = [ 14 | new Property( 15 | 'time', 16 | 'time', 17 | "The start time of the candlestick", 18 | 'primitive', 19 | 'primitives.DateTime' 20 | ), 21 | new Property( 22 | 'bid', 23 | 'bid', 24 | "The candlestick data based on bids. Only provided if bid-based candles were requested.", 25 | 'object', 26 | 'instrument.CandlestickData' 27 | ), 28 | new Property( 29 | 'ask', 30 | 'ask', 31 | "The candlestick data based on asks. Only provided if ask-based candles were requested.", 32 | 'object', 33 | 'instrument.CandlestickData' 34 | ), 35 | new Property( 36 | 'mid', 37 | 'mid', 38 | "The candlestick data based on midpoints. Only provided if midpoint-based candles were requested.", 39 | 'object', 40 | 'instrument.CandlestickData' 41 | ), 42 | new Property( 43 | 'volume', 44 | 'volume', 45 | "The number of prices created during the time-range represented by the candlestick.", 46 | 'primitive', 47 | 'integer' 48 | ), 49 | new Property( 50 | 'complete', 51 | 'complete', 52 | "A flag indicating if the candlestick is complete. A complete candlestick is one whose ending time is not in the future.", 53 | 'primitive', 54 | 'boolean' 55 | ), 56 | ]; 57 | 58 | class Candlestick extends Definition { 59 | constructor(data) { 60 | super(); 61 | 62 | this._summaryFormat = ""; 63 | 64 | this._nameFormat = ""; 65 | 66 | this._properties = Candlestick_Properties; 67 | 68 | data = data || {}; 69 | 70 | if (data['time'] !== undefined) { 71 | this.time = data['time']; 72 | } 73 | 74 | if (data['bid'] !== undefined) { 75 | this.bid = new CandlestickData(data['bid']); 76 | } 77 | 78 | if (data['ask'] !== undefined) { 79 | this.ask = new CandlestickData(data['ask']); 80 | } 81 | 82 | if (data['mid'] !== undefined) { 83 | this.mid = new CandlestickData(data['mid']); 84 | } 85 | 86 | if (data['volume'] !== undefined) { 87 | this.volume = data['volume']; 88 | } 89 | 90 | if (data['complete'] !== undefined) { 91 | this.complete = data['complete']; 92 | } 93 | 94 | } 95 | } 96 | 97 | const CandlestickData_Properties = [ 98 | new Property( 99 | 'o', 100 | 'o', 101 | "The first (open) price in the time-range represented by the candlestick.", 102 | 'primitive', 103 | 'pricing_common.PriceValue' 104 | ), 105 | new Property( 106 | 'h', 107 | 'h', 108 | "The highest price in the time-range represented by the candlestick.", 109 | 'primitive', 110 | 'pricing_common.PriceValue' 111 | ), 112 | new Property( 113 | 'l', 114 | 'l', 115 | "The lowest price in the time-range represented by the candlestick.", 116 | 'primitive', 117 | 'pricing_common.PriceValue' 118 | ), 119 | new Property( 120 | 'c', 121 | 'c', 122 | "The last (closing) price in the time-range represented by the candlestick.", 123 | 'primitive', 124 | 'pricing_common.PriceValue' 125 | ), 126 | ]; 127 | 128 | class CandlestickData extends Definition { 129 | constructor(data) { 130 | super(); 131 | 132 | this._summaryFormat = ""; 133 | 134 | this._nameFormat = ""; 135 | 136 | this._properties = CandlestickData_Properties; 137 | 138 | data = data || {}; 139 | 140 | if (data['o'] !== undefined) { 141 | this.o = data['o']; 142 | } 143 | 144 | if (data['h'] !== undefined) { 145 | this.h = data['h']; 146 | } 147 | 148 | if (data['l'] !== undefined) { 149 | this.l = data['l']; 150 | } 151 | 152 | if (data['c'] !== undefined) { 153 | this.c = data['c']; 154 | } 155 | 156 | } 157 | } 158 | 159 | const OrderBook_Properties = [ 160 | new Property( 161 | 'instrument', 162 | 'instrument', 163 | "The order book's instrument", 164 | 'primitive', 165 | 'primitives.InstrumentName' 166 | ), 167 | new Property( 168 | 'time', 169 | 'time', 170 | "The time when the order book snapshot was created.", 171 | 'primitive', 172 | 'primitives.DateTime' 173 | ), 174 | new Property( 175 | 'price', 176 | 'price', 177 | "The price (midpoint) for the order book's instrument at the time of the order book snapshot", 178 | 'primitive', 179 | 'pricing_common.PriceValue' 180 | ), 181 | new Property( 182 | 'bucketWidth', 183 | 'bucketWidth', 184 | "The price width for each bucket. Each bucket covers the price range from the bucket's price to the bucket's price + bucketWidth.", 185 | 'primitive', 186 | 'pricing_common.PriceValue' 187 | ), 188 | new Property( 189 | 'buckets', 190 | 'buckets', 191 | "The partitioned order book, divided into buckets using a default bucket width. These buckets are only provided for price ranges which actually contain order or position data.", 192 | 'array_object', 193 | 'OrderBookBucket' 194 | ), 195 | ]; 196 | 197 | class OrderBook extends Definition { 198 | constructor(data) { 199 | super(); 200 | 201 | this._summaryFormat = ""; 202 | 203 | this._nameFormat = ""; 204 | 205 | this._properties = OrderBook_Properties; 206 | 207 | data = data || {}; 208 | 209 | if (data['instrument'] !== undefined) { 210 | this.instrument = data['instrument']; 211 | } 212 | 213 | if (data['time'] !== undefined) { 214 | this.time = data['time']; 215 | } 216 | 217 | if (data['price'] !== undefined) { 218 | this.price = data['price']; 219 | } 220 | 221 | if (data['bucketWidth'] !== undefined) { 222 | this.bucketWidth = data['bucketWidth']; 223 | } 224 | 225 | if (data['buckets'] !== undefined) { 226 | this.buckets = data['buckets'].map(x => new OrderBookBucket(x)); 227 | } 228 | 229 | } 230 | } 231 | 232 | const OrderBookBucket_Properties = [ 233 | new Property( 234 | 'price', 235 | 'price', 236 | "The lowest price (inclusive) covered by the bucket. The bucket covers the price range from the price to price + the order book's bucketWidth.", 237 | 'primitive', 238 | 'pricing_common.PriceValue' 239 | ), 240 | new Property( 241 | 'longCountPercent', 242 | 'longCountPercent', 243 | "The percentage of the total number of orders represented by the long orders found in this bucket.", 244 | 'primitive', 245 | 'primitives.DecimalNumber' 246 | ), 247 | new Property( 248 | 'shortCountPercent', 249 | 'shortCountPercent', 250 | "The percentage of the total number of orders represented by the short orders found in this bucket.", 251 | 'primitive', 252 | 'primitives.DecimalNumber' 253 | ), 254 | ]; 255 | 256 | class OrderBookBucket extends Definition { 257 | constructor(data) { 258 | super(); 259 | 260 | this._summaryFormat = ""; 261 | 262 | this._nameFormat = ""; 263 | 264 | this._properties = OrderBookBucket_Properties; 265 | 266 | data = data || {}; 267 | 268 | if (data['price'] !== undefined) { 269 | this.price = data['price']; 270 | } 271 | 272 | if (data['longCountPercent'] !== undefined) { 273 | this.longCountPercent = data['longCountPercent']; 274 | } 275 | 276 | if (data['shortCountPercent'] !== undefined) { 277 | this.shortCountPercent = data['shortCountPercent']; 278 | } 279 | 280 | } 281 | } 282 | 283 | const PositionBook_Properties = [ 284 | new Property( 285 | 'instrument', 286 | 'instrument', 287 | "The position book's instrument", 288 | 'primitive', 289 | 'primitives.InstrumentName' 290 | ), 291 | new Property( 292 | 'time', 293 | 'time', 294 | "The time when the position book snapshot was created", 295 | 'primitive', 296 | 'primitives.DateTime' 297 | ), 298 | new Property( 299 | 'price', 300 | 'price', 301 | "The price (midpoint) for the position book's instrument at the time of the position book snapshot", 302 | 'primitive', 303 | 'pricing_common.PriceValue' 304 | ), 305 | new Property( 306 | 'bucketWidth', 307 | 'bucketWidth', 308 | "The price width for each bucket. Each bucket covers the price range from the bucket's price to the bucket's price + bucketWidth.", 309 | 'primitive', 310 | 'pricing_common.PriceValue' 311 | ), 312 | new Property( 313 | 'buckets', 314 | 'buckets', 315 | "The partitioned position book, divided into buckets using a default bucket width. These buckets are only provided for price ranges which actually contain order or position data.", 316 | 'array_object', 317 | 'PositionBookBucket' 318 | ), 319 | ]; 320 | 321 | class PositionBook extends Definition { 322 | constructor(data) { 323 | super(); 324 | 325 | this._summaryFormat = ""; 326 | 327 | this._nameFormat = ""; 328 | 329 | this._properties = PositionBook_Properties; 330 | 331 | data = data || {}; 332 | 333 | if (data['instrument'] !== undefined) { 334 | this.instrument = data['instrument']; 335 | } 336 | 337 | if (data['time'] !== undefined) { 338 | this.time = data['time']; 339 | } 340 | 341 | if (data['price'] !== undefined) { 342 | this.price = data['price']; 343 | } 344 | 345 | if (data['bucketWidth'] !== undefined) { 346 | this.bucketWidth = data['bucketWidth']; 347 | } 348 | 349 | if (data['buckets'] !== undefined) { 350 | this.buckets = data['buckets'].map(x => new PositionBookBucket(x)); 351 | } 352 | 353 | } 354 | } 355 | 356 | const PositionBookBucket_Properties = [ 357 | new Property( 358 | 'price', 359 | 'price', 360 | "The lowest price (inclusive) covered by the bucket. The bucket covers the price range from the price to price + the position book's bucketWidth.", 361 | 'primitive', 362 | 'pricing_common.PriceValue' 363 | ), 364 | new Property( 365 | 'longCountPercent', 366 | 'longCountPercent', 367 | "The percentage of the total number of positions represented by the long positions found in this bucket.", 368 | 'primitive', 369 | 'primitives.DecimalNumber' 370 | ), 371 | new Property( 372 | 'shortCountPercent', 373 | 'shortCountPercent', 374 | "The percentage of the total number of positions represented by the short positions found in this bucket.", 375 | 'primitive', 376 | 'primitives.DecimalNumber' 377 | ), 378 | ]; 379 | 380 | class PositionBookBucket extends Definition { 381 | constructor(data) { 382 | super(); 383 | 384 | this._summaryFormat = ""; 385 | 386 | this._nameFormat = ""; 387 | 388 | this._properties = PositionBookBucket_Properties; 389 | 390 | data = data || {}; 391 | 392 | if (data['price'] !== undefined) { 393 | this.price = data['price']; 394 | } 395 | 396 | if (data['longCountPercent'] !== undefined) { 397 | this.longCountPercent = data['longCountPercent']; 398 | } 399 | 400 | if (data['shortCountPercent'] !== undefined) { 401 | this.shortCountPercent = data['shortCountPercent']; 402 | } 403 | 404 | } 405 | } 406 | 407 | class EntitySpec { 408 | constructor(context) { 409 | this.context = context; 410 | this.Candlestick = Candlestick; 411 | this.CandlestickData = CandlestickData; 412 | this.OrderBook = OrderBook; 413 | this.OrderBookBucket = OrderBookBucket; 414 | this.PositionBook = PositionBook; 415 | this.PositionBookBucket = PositionBookBucket; 416 | } 417 | 418 | candles( 419 | instrument, 420 | queryParams, 421 | responseHandler 422 | ) 423 | { 424 | if (!responseHandler) 425 | { 426 | throw "No responseHandler provided for API call" 427 | } 428 | 429 | 430 | let path = '/v3/instruments/{instrument}/candles'; 431 | 432 | queryParams = queryParams || {}; 433 | 434 | path = path.replace('{' + 'instrument' + '}', instrument); 435 | 436 | path = path + "?"; 437 | if (typeof queryParams['price'] !== 'undefined') { 438 | path = path + "price=" + queryParams['price'] + "&"; 439 | } 440 | if (typeof queryParams['granularity'] !== 'undefined') { 441 | path = path + "granularity=" + queryParams['granularity'] + "&"; 442 | } 443 | if (typeof queryParams['count'] !== 'undefined') { 444 | path = path + "count=" + queryParams['count'] + "&"; 445 | } 446 | if (typeof queryParams['from'] !== 'undefined') { 447 | path = path + "from=" + queryParams['from'] + "&"; 448 | } 449 | if (typeof queryParams['to'] !== 'undefined') { 450 | path = path + "to=" + queryParams['to'] + "&"; 451 | } 452 | if (typeof queryParams['smooth'] !== 'undefined') { 453 | path = path + "smooth=" + queryParams['smooth'] + "&"; 454 | } 455 | if (typeof queryParams['includeFirst'] !== 'undefined') { 456 | path = path + "includeFirst=" + queryParams['includeFirst'] + "&"; 457 | } 458 | if (typeof queryParams['dailyAlignment'] !== 'undefined') { 459 | path = path + "dailyAlignment=" + queryParams['dailyAlignment'] + "&"; 460 | } 461 | if (typeof queryParams['alignmentTimezone'] !== 'undefined') { 462 | path = path + "alignmentTimezone=" + queryParams['alignmentTimezone'] + "&"; 463 | } 464 | if (typeof queryParams['weeklyAlignment'] !== 'undefined') { 465 | path = path + "weeklyAlignment=" + queryParams['weeklyAlignment'] + "&"; 466 | } 467 | 468 | let body = {}; 469 | 470 | let handleResponse = (response) => { 471 | if (response.contentType.startsWith("application/json")) 472 | { 473 | let msg = JSON.parse(response.rawBody); 474 | 475 | response.body = {}; 476 | 477 | if (response.statusCode == 200) 478 | { 479 | if (msg['instrument'] !== undefined) { 480 | response.body.instrument = msg['instrument']; 481 | } 482 | 483 | if (msg['granularity'] !== undefined) { 484 | response.body.granularity = msg['granularity']; 485 | } 486 | 487 | if (msg['candles'] !== undefined) { 488 | response.body.candles = msg['candles'].map(x => new Candlestick(x)); 489 | } 490 | 491 | } 492 | else if (response.statusCode == 400) 493 | { 494 | } 495 | else if (response.statusCode == 401) 496 | { 497 | } 498 | else if (response.statusCode == 404) 499 | { 500 | } 501 | else if (response.statusCode == 405) 502 | { 503 | } 504 | // 505 | // Assume standard error response with errorCode and errorMessage 506 | // 507 | else 508 | { 509 | if (msg['errorCode'] !== undefined) { 510 | response.body.errorCode = msg['errorCode']; 511 | } 512 | 513 | if (msg['errorMessage'] !== undefined) { 514 | response.body.errorMessage = msg['errorMessage']; 515 | } 516 | } 517 | } 518 | 519 | responseHandler(response); 520 | }; 521 | 522 | 523 | this.context.request( 524 | 'GET', 525 | path, 526 | body, 527 | undefined, 528 | handleResponse 529 | ); 530 | } 531 | 532 | price( 533 | instrument, 534 | queryParams, 535 | responseHandler 536 | ) 537 | { 538 | if (!responseHandler) 539 | { 540 | throw "No responseHandler provided for API call" 541 | } 542 | 543 | 544 | let path = '/v3/instruments/{instrument}/price'; 545 | 546 | queryParams = queryParams || {}; 547 | 548 | path = path.replace('{' + 'instrument' + '}', instrument); 549 | 550 | path = path + "?"; 551 | if (typeof queryParams['time'] !== 'undefined') { 552 | path = path + "time=" + queryParams['time'] + "&"; 553 | } 554 | 555 | let body = {}; 556 | 557 | let handleResponse = (response) => { 558 | if (response.contentType.startsWith("application/json")) 559 | { 560 | let msg = JSON.parse(response.rawBody); 561 | 562 | response.body = {}; 563 | 564 | if (response.statusCode == 200) 565 | { 566 | if (msg['price'] !== undefined) { 567 | response.body.price = new pricing_common.Price(msg['price']); 568 | } 569 | 570 | } 571 | else if (response.statusCode == 400) 572 | { 573 | } 574 | else if (response.statusCode == 401) 575 | { 576 | } 577 | else if (response.statusCode == 404) 578 | { 579 | } 580 | else if (response.statusCode == 405) 581 | { 582 | } 583 | // 584 | // Assume standard error response with errorCode and errorMessage 585 | // 586 | else 587 | { 588 | if (msg['errorCode'] !== undefined) { 589 | response.body.errorCode = msg['errorCode']; 590 | } 591 | 592 | if (msg['errorMessage'] !== undefined) { 593 | response.body.errorMessage = msg['errorMessage']; 594 | } 595 | } 596 | } 597 | 598 | responseHandler(response); 599 | }; 600 | 601 | 602 | this.context.request( 603 | 'GET', 604 | path, 605 | body, 606 | undefined, 607 | handleResponse 608 | ); 609 | } 610 | 611 | prices( 612 | instrument, 613 | queryParams, 614 | responseHandler 615 | ) 616 | { 617 | if (!responseHandler) 618 | { 619 | throw "No responseHandler provided for API call" 620 | } 621 | 622 | 623 | let path = '/v3/instruments/{instrument}/price/range'; 624 | 625 | queryParams = queryParams || {}; 626 | 627 | path = path.replace('{' + 'instrument' + '}', instrument); 628 | 629 | path = path + "?"; 630 | if (typeof queryParams['from'] !== 'undefined') { 631 | path = path + "from=" + queryParams['from'] + "&"; 632 | } 633 | if (typeof queryParams['to'] !== 'undefined') { 634 | path = path + "to=" + queryParams['to'] + "&"; 635 | } 636 | 637 | let body = {}; 638 | 639 | let handleResponse = (response) => { 640 | if (response.contentType.startsWith("application/json")) 641 | { 642 | let msg = JSON.parse(response.rawBody); 643 | 644 | response.body = {}; 645 | 646 | if (response.statusCode == 200) 647 | { 648 | if (msg['prices'] !== undefined) { 649 | response.body.prices = msg['prices'].map(x => new pricing_common.Price(x)); 650 | } 651 | 652 | } 653 | else if (response.statusCode == 400) 654 | { 655 | } 656 | else if (response.statusCode == 401) 657 | { 658 | } 659 | else if (response.statusCode == 404) 660 | { 661 | } 662 | else if (response.statusCode == 405) 663 | { 664 | } 665 | // 666 | // Assume standard error response with errorCode and errorMessage 667 | // 668 | else 669 | { 670 | if (msg['errorCode'] !== undefined) { 671 | response.body.errorCode = msg['errorCode']; 672 | } 673 | 674 | if (msg['errorMessage'] !== undefined) { 675 | response.body.errorMessage = msg['errorMessage']; 676 | } 677 | } 678 | } 679 | 680 | responseHandler(response); 681 | }; 682 | 683 | 684 | this.context.request( 685 | 'GET', 686 | path, 687 | body, 688 | undefined, 689 | handleResponse 690 | ); 691 | } 692 | 693 | orderBook( 694 | instrument, 695 | queryParams, 696 | responseHandler 697 | ) 698 | { 699 | if (!responseHandler) 700 | { 701 | throw "No responseHandler provided for API call" 702 | } 703 | 704 | 705 | let path = '/v3/instruments/{instrument}/orderBook'; 706 | 707 | queryParams = queryParams || {}; 708 | 709 | path = path.replace('{' + 'instrument' + '}', instrument); 710 | 711 | path = path + "?"; 712 | if (typeof queryParams['time'] !== 'undefined') { 713 | path = path + "time=" + queryParams['time'] + "&"; 714 | } 715 | 716 | let body = {}; 717 | 718 | let handleResponse = (response) => { 719 | if (response.contentType.startsWith("application/json")) 720 | { 721 | let msg = JSON.parse(response.rawBody); 722 | 723 | response.body = {}; 724 | 725 | if (response.statusCode == 200) 726 | { 727 | if (msg['orderBook'] !== undefined) { 728 | response.body.orderBook = new OrderBook(msg['orderBook']); 729 | } 730 | 731 | } 732 | else if (response.statusCode == 400) 733 | { 734 | } 735 | else if (response.statusCode == 401) 736 | { 737 | } 738 | else if (response.statusCode == 404) 739 | { 740 | } 741 | else if (response.statusCode == 405) 742 | { 743 | } 744 | // 745 | // Assume standard error response with errorCode and errorMessage 746 | // 747 | else 748 | { 749 | if (msg['errorCode'] !== undefined) { 750 | response.body.errorCode = msg['errorCode']; 751 | } 752 | 753 | if (msg['errorMessage'] !== undefined) { 754 | response.body.errorMessage = msg['errorMessage']; 755 | } 756 | } 757 | } 758 | 759 | responseHandler(response); 760 | }; 761 | 762 | 763 | this.context.request( 764 | 'GET', 765 | path, 766 | body, 767 | undefined, 768 | handleResponse 769 | ); 770 | } 771 | 772 | positionBook( 773 | instrument, 774 | queryParams, 775 | responseHandler 776 | ) 777 | { 778 | if (!responseHandler) 779 | { 780 | throw "No responseHandler provided for API call" 781 | } 782 | 783 | 784 | let path = '/v3/instruments/{instrument}/positionBook'; 785 | 786 | queryParams = queryParams || {}; 787 | 788 | path = path.replace('{' + 'instrument' + '}', instrument); 789 | 790 | path = path + "?"; 791 | if (typeof queryParams['time'] !== 'undefined') { 792 | path = path + "time=" + queryParams['time'] + "&"; 793 | } 794 | 795 | let body = {}; 796 | 797 | let handleResponse = (response) => { 798 | if (response.contentType.startsWith("application/json")) 799 | { 800 | let msg = JSON.parse(response.rawBody); 801 | 802 | response.body = {}; 803 | 804 | if (response.statusCode == 200) 805 | { 806 | if (msg['positionBook'] !== undefined) { 807 | response.body.positionBook = new PositionBook(msg['positionBook']); 808 | } 809 | 810 | } 811 | else if (response.statusCode == 400) 812 | { 813 | } 814 | else if (response.statusCode == 401) 815 | { 816 | } 817 | else if (response.statusCode == 404) 818 | { 819 | } 820 | else if (response.statusCode == 405) 821 | { 822 | } 823 | // 824 | // Assume standard error response with errorCode and errorMessage 825 | // 826 | else 827 | { 828 | if (msg['errorCode'] !== undefined) { 829 | response.body.errorCode = msg['errorCode']; 830 | } 831 | 832 | if (msg['errorMessage'] !== undefined) { 833 | response.body.errorMessage = msg['errorMessage']; 834 | } 835 | } 836 | } 837 | 838 | responseHandler(response); 839 | }; 840 | 841 | 842 | this.context.request( 843 | 'GET', 844 | path, 845 | body, 846 | undefined, 847 | handleResponse 848 | ); 849 | } 850 | 851 | 852 | 853 | } 854 | 855 | exports.Candlestick = Candlestick; 856 | exports.CandlestickData = CandlestickData; 857 | exports.OrderBook = OrderBook; 858 | exports.OrderBookBucket = OrderBookBucket; 859 | exports.PositionBook = PositionBook; 860 | exports.PositionBookBucket = PositionBookBucket; 861 | 862 | exports.EntitySpec = EntitySpec; 863 | -------------------------------------------------------------------------------- /src/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@oanda/v20", 3 | "description": "OANDA v20 bindings for Javascript", 4 | "version": "3.0.25-0", 5 | "author": "OANDA Corporation", 6 | "license": "MIT", 7 | "homepage": "http://developer.oanda.com/rest-live-v20/introduction" 8 | } 9 | -------------------------------------------------------------------------------- /src/position.js: -------------------------------------------------------------------------------- 1 | /* jshint esversion: 6 */ 2 | 3 | "use strict"; 4 | 5 | var Definition = require('./base').Definition; 6 | var Property = require('./base').Property; 7 | var Field = require('./base').Field; 8 | 9 | var transaction = require('./transaction'); 10 | 11 | 12 | 13 | const Position_Properties = [ 14 | new Property( 15 | 'instrument', 16 | "Instrument", 17 | "The Position's Instrument.", 18 | 'primitive', 19 | 'primitives.InstrumentName' 20 | ), 21 | new Property( 22 | 'pl', 23 | "Profit/Loss", 24 | "Profit/loss realized by the Position over the lifetime of the Account.", 25 | 'primitive', 26 | 'primitives.AccountUnits' 27 | ), 28 | new Property( 29 | 'unrealizedPL', 30 | "Unrealized Profit/Loss", 31 | "The unrealized profit/loss of all open Trades that contribute to this Position.", 32 | 'primitive', 33 | 'primitives.AccountUnits' 34 | ), 35 | new Property( 36 | 'marginUsed', 37 | "Margin Used", 38 | "Margin currently used by the Position.", 39 | 'primitive', 40 | 'primitives.AccountUnits' 41 | ), 42 | new Property( 43 | 'resettablePL', 44 | "Resettable Profit/Loss", 45 | "Profit/loss realized by the Position since the Account's resettablePL was last reset by the client.", 46 | 'primitive', 47 | 'primitives.AccountUnits' 48 | ), 49 | new Property( 50 | 'financing', 51 | "Financing", 52 | "The total amount of financing paid/collected for this instrument over the lifetime of the Account.", 53 | 'primitive', 54 | 'primitives.AccountUnits' 55 | ), 56 | new Property( 57 | 'commission', 58 | "Commission", 59 | "The total amount of commission paid for this instrument over the lifetime of the Account.", 60 | 'primitive', 61 | 'primitives.AccountUnits' 62 | ), 63 | new Property( 64 | 'guaranteedExecutionFees', 65 | "Guranteed Execution Fee", 66 | "The total amount of fees charged over the lifetime of the Account for the execution of guaranteed Stop Loss Orders for this instrument.", 67 | 'primitive', 68 | 'primitives.AccountUnits' 69 | ), 70 | new Property( 71 | 'long', 72 | "Long Side", 73 | "The details of the long side of the Position.", 74 | 'object', 75 | 'position.PositionSide' 76 | ), 77 | new Property( 78 | 'short', 79 | "Short Side", 80 | "The details of the short side of the Position.", 81 | 'object', 82 | 'position.PositionSide' 83 | ), 84 | ]; 85 | 86 | class Position extends Definition { 87 | constructor(data) { 88 | super(); 89 | 90 | this._summaryFormat = "{instrument}, {pl} PL {unrealizedPL} UPL"; 91 | 92 | this._nameFormat = "Position"; 93 | 94 | this._properties = Position_Properties; 95 | 96 | data = data || {}; 97 | 98 | if (data['instrument'] !== undefined) { 99 | this.instrument = data['instrument']; 100 | } 101 | 102 | if (data['pl'] !== undefined) { 103 | this.pl = data['pl']; 104 | } 105 | 106 | if (data['unrealizedPL'] !== undefined) { 107 | this.unrealizedPL = data['unrealizedPL']; 108 | } 109 | 110 | if (data['marginUsed'] !== undefined) { 111 | this.marginUsed = data['marginUsed']; 112 | } 113 | 114 | if (data['resettablePL'] !== undefined) { 115 | this.resettablePL = data['resettablePL']; 116 | } 117 | 118 | if (data['financing'] !== undefined) { 119 | this.financing = data['financing']; 120 | } 121 | 122 | if (data['commission'] !== undefined) { 123 | this.commission = data['commission']; 124 | } 125 | 126 | if (data['guaranteedExecutionFees'] !== undefined) { 127 | this.guaranteedExecutionFees = data['guaranteedExecutionFees']; 128 | } 129 | 130 | if (data['long'] !== undefined) { 131 | this.long = new PositionSide(data['long']); 132 | } 133 | 134 | if (data['short'] !== undefined) { 135 | this.short = new PositionSide(data['short']); 136 | } 137 | 138 | } 139 | } 140 | 141 | const PositionSide_Properties = [ 142 | new Property( 143 | 'units', 144 | "Units", 145 | "Number of units in the position (negative value indicates short position, positive indicates long position).", 146 | 'primitive', 147 | 'primitives.DecimalNumber' 148 | ), 149 | new Property( 150 | 'averagePrice', 151 | "Average Price", 152 | "Volume-weighted average of the underlying Trade open prices for the Position.", 153 | 'primitive', 154 | 'pricing_common.PriceValue' 155 | ), 156 | new Property( 157 | 'tradeIDs', 158 | "Trade IDs", 159 | "List of the open Trade IDs which contribute to the open Position.", 160 | 'array_primitive', 161 | 'TradeID' 162 | ), 163 | new Property( 164 | 'pl', 165 | "Profit/Loss", 166 | "Profit/loss realized by the PositionSide over the lifetime of the Account.", 167 | 'primitive', 168 | 'primitives.AccountUnits' 169 | ), 170 | new Property( 171 | 'unrealizedPL', 172 | "Unrealized Profit/Loss", 173 | "The unrealized profit/loss of all open Trades that contribute to this PositionSide.", 174 | 'primitive', 175 | 'primitives.AccountUnits' 176 | ), 177 | new Property( 178 | 'resettablePL', 179 | "Resettable Profit/Loss", 180 | "Profit/loss realized by the PositionSide since the Account's resettablePL was last reset by the client.", 181 | 'primitive', 182 | 'primitives.AccountUnits' 183 | ), 184 | new Property( 185 | 'financing', 186 | "Financing", 187 | "The total amount of financing paid/collected for this PositionSide over the lifetime of the Account.", 188 | 'primitive', 189 | 'primitives.AccountUnits' 190 | ), 191 | new Property( 192 | 'guaranteedExecutionFees', 193 | "Guranteed Execution Fees", 194 | "The total amount of fees charged over the lifetime of the Account for the execution of guaranteed Stop Loss Orders attached to Trades for this PositionSide.", 195 | 'primitive', 196 | 'primitives.AccountUnits' 197 | ), 198 | ]; 199 | 200 | class PositionSide extends Definition { 201 | constructor(data) { 202 | super(); 203 | 204 | this._summaryFormat = "{units} @ {averagePrice}, {pl} PL {unrealizedPL} UPL"; 205 | 206 | this._nameFormat = ""; 207 | 208 | this._properties = PositionSide_Properties; 209 | 210 | data = data || {}; 211 | 212 | if (data['units'] !== undefined) { 213 | this.units = data['units']; 214 | } 215 | 216 | if (data['averagePrice'] !== undefined) { 217 | this.averagePrice = data['averagePrice']; 218 | } 219 | 220 | if (data['tradeIDs'] !== undefined) { 221 | this.tradeIDs = data['tradeIDs']; 222 | } 223 | 224 | if (data['pl'] !== undefined) { 225 | this.pl = data['pl']; 226 | } 227 | 228 | if (data['unrealizedPL'] !== undefined) { 229 | this.unrealizedPL = data['unrealizedPL']; 230 | } 231 | 232 | if (data['resettablePL'] !== undefined) { 233 | this.resettablePL = data['resettablePL']; 234 | } 235 | 236 | if (data['financing'] !== undefined) { 237 | this.financing = data['financing']; 238 | } 239 | 240 | if (data['guaranteedExecutionFees'] !== undefined) { 241 | this.guaranteedExecutionFees = data['guaranteedExecutionFees']; 242 | } 243 | 244 | } 245 | } 246 | 247 | const CalculatedPositionState_Properties = [ 248 | new Property( 249 | 'instrument', 250 | "Instrument", 251 | "The Position's Instrument.", 252 | 'primitive', 253 | 'primitives.InstrumentName' 254 | ), 255 | new Property( 256 | 'netUnrealizedPL', 257 | "Net Unrealized Profit/Loss", 258 | "The Position's net unrealized profit/loss", 259 | 'primitive', 260 | 'primitives.AccountUnits' 261 | ), 262 | new Property( 263 | 'longUnrealizedPL', 264 | "Long Unrealized Profit/Loss", 265 | "The unrealized profit/loss of the Position's long open Trades", 266 | 'primitive', 267 | 'primitives.AccountUnits' 268 | ), 269 | new Property( 270 | 'shortUnrealizedPL', 271 | "Short Unrealized Profit/Loss", 272 | "The unrealized profit/loss of the Position's short open Trades", 273 | 'primitive', 274 | 'primitives.AccountUnits' 275 | ), 276 | new Property( 277 | 'marginUsed', 278 | "Margin Used", 279 | "Margin currently used by the Position.", 280 | 'primitive', 281 | 'primitives.AccountUnits' 282 | ), 283 | ]; 284 | 285 | class CalculatedPositionState extends Definition { 286 | constructor(data) { 287 | super(); 288 | 289 | this._summaryFormat = ""; 290 | 291 | this._nameFormat = ""; 292 | 293 | this._properties = CalculatedPositionState_Properties; 294 | 295 | data = data || {}; 296 | 297 | if (data['instrument'] !== undefined) { 298 | this.instrument = data['instrument']; 299 | } 300 | 301 | if (data['netUnrealizedPL'] !== undefined) { 302 | this.netUnrealizedPL = data['netUnrealizedPL']; 303 | } 304 | 305 | if (data['longUnrealizedPL'] !== undefined) { 306 | this.longUnrealizedPL = data['longUnrealizedPL']; 307 | } 308 | 309 | if (data['shortUnrealizedPL'] !== undefined) { 310 | this.shortUnrealizedPL = data['shortUnrealizedPL']; 311 | } 312 | 313 | if (data['marginUsed'] !== undefined) { 314 | this.marginUsed = data['marginUsed']; 315 | } 316 | 317 | } 318 | } 319 | 320 | class EntitySpec { 321 | constructor(context) { 322 | this.context = context; 323 | this.Position = Position; 324 | this.PositionSide = PositionSide; 325 | this.CalculatedPositionState = CalculatedPositionState; 326 | } 327 | 328 | list( 329 | accountID, 330 | responseHandler 331 | ) 332 | { 333 | if (!responseHandler) 334 | { 335 | throw "No responseHandler provided for API call" 336 | } 337 | 338 | 339 | let path = '/v3/accounts/{accountID}/positions'; 340 | 341 | 342 | path = path.replace('{' + 'accountID' + '}', accountID); 343 | 344 | 345 | let body = {}; 346 | 347 | let handleResponse = (response) => { 348 | if (response.contentType.startsWith("application/json")) 349 | { 350 | let msg = JSON.parse(response.rawBody); 351 | 352 | response.body = {}; 353 | 354 | if (response.statusCode == 200) 355 | { 356 | if (msg['positions'] !== undefined) { 357 | response.body.positions = msg['positions'].map(x => new Position(x)); 358 | } 359 | 360 | if (msg['lastTransactionID'] !== undefined) { 361 | response.body.lastTransactionID = msg['lastTransactionID']; 362 | } 363 | 364 | } 365 | else if (response.statusCode == 401) 366 | { 367 | } 368 | else if (response.statusCode == 404) 369 | { 370 | } 371 | else if (response.statusCode == 405) 372 | { 373 | } 374 | // 375 | // Assume standard error response with errorCode and errorMessage 376 | // 377 | else 378 | { 379 | if (msg['errorCode'] !== undefined) { 380 | response.body.errorCode = msg['errorCode']; 381 | } 382 | 383 | if (msg['errorMessage'] !== undefined) { 384 | response.body.errorMessage = msg['errorMessage']; 385 | } 386 | } 387 | } 388 | 389 | responseHandler(response); 390 | }; 391 | 392 | 393 | this.context.request( 394 | 'GET', 395 | path, 396 | body, 397 | undefined, 398 | handleResponse 399 | ); 400 | } 401 | 402 | listOpen( 403 | accountID, 404 | responseHandler 405 | ) 406 | { 407 | if (!responseHandler) 408 | { 409 | throw "No responseHandler provided for API call" 410 | } 411 | 412 | 413 | let path = '/v3/accounts/{accountID}/openPositions'; 414 | 415 | 416 | path = path.replace('{' + 'accountID' + '}', accountID); 417 | 418 | 419 | let body = {}; 420 | 421 | let handleResponse = (response) => { 422 | if (response.contentType.startsWith("application/json")) 423 | { 424 | let msg = JSON.parse(response.rawBody); 425 | 426 | response.body = {}; 427 | 428 | if (response.statusCode == 200) 429 | { 430 | if (msg['positions'] !== undefined) { 431 | response.body.positions = msg['positions'].map(x => new Position(x)); 432 | } 433 | 434 | if (msg['lastTransactionID'] !== undefined) { 435 | response.body.lastTransactionID = msg['lastTransactionID']; 436 | } 437 | 438 | } 439 | else if (response.statusCode == 401) 440 | { 441 | } 442 | else if (response.statusCode == 404) 443 | { 444 | } 445 | else if (response.statusCode == 405) 446 | { 447 | } 448 | // 449 | // Assume standard error response with errorCode and errorMessage 450 | // 451 | else 452 | { 453 | if (msg['errorCode'] !== undefined) { 454 | response.body.errorCode = msg['errorCode']; 455 | } 456 | 457 | if (msg['errorMessage'] !== undefined) { 458 | response.body.errorMessage = msg['errorMessage']; 459 | } 460 | } 461 | } 462 | 463 | responseHandler(response); 464 | }; 465 | 466 | 467 | this.context.request( 468 | 'GET', 469 | path, 470 | body, 471 | undefined, 472 | handleResponse 473 | ); 474 | } 475 | 476 | get( 477 | accountID, 478 | instrument, 479 | responseHandler 480 | ) 481 | { 482 | if (!responseHandler) 483 | { 484 | throw "No responseHandler provided for API call" 485 | } 486 | 487 | 488 | let path = '/v3/accounts/{accountID}/positions/{instrument}'; 489 | 490 | 491 | path = path.replace('{' + 'accountID' + '}', accountID); 492 | path = path.replace('{' + 'instrument' + '}', instrument); 493 | 494 | 495 | let body = {}; 496 | 497 | let handleResponse = (response) => { 498 | if (response.contentType.startsWith("application/json")) 499 | { 500 | let msg = JSON.parse(response.rawBody); 501 | 502 | response.body = {}; 503 | 504 | if (response.statusCode == 200) 505 | { 506 | if (msg['position'] !== undefined) { 507 | response.body.position = new Position(msg['position']); 508 | } 509 | 510 | if (msg['lastTransactionID'] !== undefined) { 511 | response.body.lastTransactionID = msg['lastTransactionID']; 512 | } 513 | 514 | } 515 | else if (response.statusCode == 401) 516 | { 517 | } 518 | else if (response.statusCode == 404) 519 | { 520 | } 521 | else if (response.statusCode == 405) 522 | { 523 | } 524 | // 525 | // Assume standard error response with errorCode and errorMessage 526 | // 527 | else 528 | { 529 | if (msg['errorCode'] !== undefined) { 530 | response.body.errorCode = msg['errorCode']; 531 | } 532 | 533 | if (msg['errorMessage'] !== undefined) { 534 | response.body.errorMessage = msg['errorMessage']; 535 | } 536 | } 537 | } 538 | 539 | responseHandler(response); 540 | }; 541 | 542 | 543 | this.context.request( 544 | 'GET', 545 | path, 546 | body, 547 | undefined, 548 | handleResponse 549 | ); 550 | } 551 | 552 | close( 553 | accountID, 554 | instrument, 555 | bodyParams, 556 | responseHandler 557 | ) 558 | { 559 | if (!responseHandler) 560 | { 561 | throw "No responseHandler provided for API call" 562 | } 563 | 564 | 565 | let path = '/v3/accounts/{accountID}/positions/{instrument}/close'; 566 | 567 | bodyParams = bodyParams || {}; 568 | 569 | path = path.replace('{' + 'accountID' + '}', accountID); 570 | path = path.replace('{' + 'instrument' + '}', instrument); 571 | 572 | 573 | let body = {}; 574 | 575 | if (typeof bodyParams['longUnits'] !== 'undefined') 576 | { 577 | body['longUnits'] = bodyParams['longUnits']; 578 | } 579 | 580 | if (typeof bodyParams['longClientExtensions'] !== 'undefined') 581 | { 582 | body['longClientExtensions'] = bodyParams['longClientExtensions']; 583 | } 584 | 585 | if (typeof bodyParams['shortUnits'] !== 'undefined') 586 | { 587 | body['shortUnits'] = bodyParams['shortUnits']; 588 | } 589 | 590 | if (typeof bodyParams['shortClientExtensions'] !== 'undefined') 591 | { 592 | body['shortClientExtensions'] = bodyParams['shortClientExtensions']; 593 | } 594 | 595 | let handleResponse = (response) => { 596 | if (response.contentType.startsWith("application/json")) 597 | { 598 | let msg = JSON.parse(response.rawBody); 599 | 600 | response.body = {}; 601 | 602 | if (response.statusCode == 200) 603 | { 604 | if (msg['longOrderCreateTransaction'] !== undefined) { 605 | response.body.longOrderCreateTransaction = new transaction.MarketOrderTransaction(msg['longOrderCreateTransaction']); 606 | } 607 | 608 | if (msg['longOrderFillTransaction'] !== undefined) { 609 | response.body.longOrderFillTransaction = new transaction.OrderFillTransaction(msg['longOrderFillTransaction']); 610 | } 611 | 612 | if (msg['longOrderCancelTransaction'] !== undefined) { 613 | response.body.longOrderCancelTransaction = new transaction.OrderCancelTransaction(msg['longOrderCancelTransaction']); 614 | } 615 | 616 | if (msg['shortOrderCreateTransaction'] !== undefined) { 617 | response.body.shortOrderCreateTransaction = new transaction.MarketOrderTransaction(msg['shortOrderCreateTransaction']); 618 | } 619 | 620 | if (msg['shortOrderFillTransaction'] !== undefined) { 621 | response.body.shortOrderFillTransaction = new transaction.OrderFillTransaction(msg['shortOrderFillTransaction']); 622 | } 623 | 624 | if (msg['shortOrderCancelTransaction'] !== undefined) { 625 | response.body.shortOrderCancelTransaction = new transaction.OrderCancelTransaction(msg['shortOrderCancelTransaction']); 626 | } 627 | 628 | if (msg['relatedTransactionIDs'] !== undefined) { 629 | response.body.relatedTransactionIDs = msg['relatedTransactionIDs']; 630 | } 631 | 632 | if (msg['lastTransactionID'] !== undefined) { 633 | response.body.lastTransactionID = msg['lastTransactionID']; 634 | } 635 | 636 | } 637 | else if (response.statusCode == 400) 638 | { 639 | if (msg['longOrderRejectTransaction'] !== undefined) { 640 | response.body.longOrderRejectTransaction = new transaction.MarketOrderRejectTransaction(msg['longOrderRejectTransaction']); 641 | } 642 | 643 | if (msg['shortOrderRejectTransaction'] !== undefined) { 644 | response.body.shortOrderRejectTransaction = new transaction.MarketOrderRejectTransaction(msg['shortOrderRejectTransaction']); 645 | } 646 | 647 | if (msg['relatedTransactionIDs'] !== undefined) { 648 | response.body.relatedTransactionIDs = msg['relatedTransactionIDs']; 649 | } 650 | 651 | if (msg['lastTransactionID'] !== undefined) { 652 | response.body.lastTransactionID = msg['lastTransactionID']; 653 | } 654 | 655 | if (msg['errorCode'] !== undefined) { 656 | response.body.errorCode = msg['errorCode']; 657 | } 658 | 659 | if (msg['errorMessage'] !== undefined) { 660 | response.body.errorMessage = msg['errorMessage']; 661 | } 662 | 663 | } 664 | else if (response.statusCode == 401) 665 | { 666 | } 667 | else if (response.statusCode == 404) 668 | { 669 | if (msg['longOrderRejectTransaction'] !== undefined) { 670 | response.body.longOrderRejectTransaction = new transaction.MarketOrderRejectTransaction(msg['longOrderRejectTransaction']); 671 | } 672 | 673 | if (msg['shortOrderRejectTransaction'] !== undefined) { 674 | response.body.shortOrderRejectTransaction = new transaction.MarketOrderRejectTransaction(msg['shortOrderRejectTransaction']); 675 | } 676 | 677 | if (msg['relatedTransactionIDs'] !== undefined) { 678 | response.body.relatedTransactionIDs = msg['relatedTransactionIDs']; 679 | } 680 | 681 | if (msg['lastTransactionID'] !== undefined) { 682 | response.body.lastTransactionID = msg['lastTransactionID']; 683 | } 684 | 685 | if (msg['errorCode'] !== undefined) { 686 | response.body.errorCode = msg['errorCode']; 687 | } 688 | 689 | if (msg['errorMessage'] !== undefined) { 690 | response.body.errorMessage = msg['errorMessage']; 691 | } 692 | 693 | } 694 | else if (response.statusCode == 405) 695 | { 696 | } 697 | // 698 | // Assume standard error response with errorCode and errorMessage 699 | // 700 | else 701 | { 702 | if (msg['errorCode'] !== undefined) { 703 | response.body.errorCode = msg['errorCode']; 704 | } 705 | 706 | if (msg['errorMessage'] !== undefined) { 707 | response.body.errorMessage = msg['errorMessage']; 708 | } 709 | } 710 | } 711 | 712 | responseHandler(response); 713 | }; 714 | 715 | 716 | this.context.request( 717 | 'PUT', 718 | path, 719 | body, 720 | undefined, 721 | handleResponse 722 | ); 723 | } 724 | 725 | 726 | 727 | } 728 | 729 | exports.Position = Position; 730 | exports.PositionSide = PositionSide; 731 | exports.CalculatedPositionState = CalculatedPositionState; 732 | 733 | exports.EntitySpec = EntitySpec; 734 | -------------------------------------------------------------------------------- /src/pricing.js: -------------------------------------------------------------------------------- 1 | /* jshint esversion: 6 */ 2 | 3 | "use strict"; 4 | 5 | var Definition = require('./base').Definition; 6 | var Property = require('./base').Property; 7 | var Field = require('./base').Field; 8 | 9 | var pricing_common = require('./pricing_common'); 10 | var order = require('./order'); 11 | var instrument = require('./instrument'); 12 | 13 | 14 | 15 | const ClientPrice_Properties = [ 16 | new Property( 17 | 'type', 18 | "Type", 19 | "The string \"PRICE\". Used to identify the a Price object when found in a stream.", 20 | 'primitive', 21 | 'string' 22 | ), 23 | new Property( 24 | 'instrument', 25 | "Instrument", 26 | "The Price's Instrument.", 27 | 'primitive', 28 | 'primitives.InstrumentName' 29 | ), 30 | new Property( 31 | 'time', 32 | "Time", 33 | "The date/time when the Price was created", 34 | 'primitive', 35 | 'primitives.DateTime' 36 | ), 37 | new Property( 38 | 'status', 39 | "Status", 40 | "The status of the Price.", 41 | 'primitive', 42 | 'pricing.PriceStatus' 43 | ), 44 | new Property( 45 | 'tradeable', 46 | "Is Tradeable", 47 | "Flag indicating if the Price is tradeable or not", 48 | 'primitive', 49 | 'boolean' 50 | ), 51 | new Property( 52 | 'bids', 53 | "Bids", 54 | "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.", 55 | 'array_object', 56 | 'PriceBucket' 57 | ), 58 | new Property( 59 | 'asks', 60 | "Asks", 61 | "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.", 62 | 'array_object', 63 | 'PriceBucket' 64 | ), 65 | new Property( 66 | 'closeoutBid', 67 | "Closeout Bid", 68 | "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.", 69 | 'primitive', 70 | 'pricing_common.PriceValue' 71 | ), 72 | new Property( 73 | 'closeoutAsk', 74 | "Closeout Ask", 75 | "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.", 76 | 'primitive', 77 | 'pricing_common.PriceValue' 78 | ), 79 | new Property( 80 | 'quoteHomeConversionFactors', 81 | "Quote Home Conversions", 82 | "The factors used to convert quantities of this price's Instrument's quote currency into a quantity of the Account's home currency. When the includeHomeConversions is present in the pricing request (regardless of its value), this field will not be present.", 83 | 'object', 84 | 'pricing.QuoteHomeConversionFactors' 85 | ), 86 | new Property( 87 | 'unitsAvailable', 88 | "Units Available", 89 | "Representation of how many units of an Instrument are available to be traded by an Order depending on its postionFill option.", 90 | 'object', 91 | 'order.UnitsAvailable' 92 | ), 93 | ]; 94 | 95 | class ClientPrice extends Definition { 96 | constructor(data) { 97 | super(); 98 | 99 | this._summaryFormat = ""; 100 | 101 | this._nameFormat = ""; 102 | 103 | this._properties = ClientPrice_Properties; 104 | 105 | data = data || {}; 106 | 107 | if (data['type'] !== undefined) { 108 | this.type = data['type']; 109 | } 110 | else { 111 | this.type = "PRICE"; 112 | } 113 | 114 | if (data['instrument'] !== undefined) { 115 | this.instrument = data['instrument']; 116 | } 117 | 118 | if (data['time'] !== undefined) { 119 | this.time = data['time']; 120 | } 121 | 122 | if (data['status'] !== undefined) { 123 | this.status = data['status']; 124 | } 125 | 126 | if (data['tradeable'] !== undefined) { 127 | this.tradeable = data['tradeable']; 128 | } 129 | 130 | if (data['bids'] !== undefined) { 131 | this.bids = data['bids'].map(x => new pricing_common.PriceBucket(x)); 132 | } 133 | 134 | if (data['asks'] !== undefined) { 135 | this.asks = data['asks'].map(x => new pricing_common.PriceBucket(x)); 136 | } 137 | 138 | if (data['closeoutBid'] !== undefined) { 139 | this.closeoutBid = data['closeoutBid']; 140 | } 141 | 142 | if (data['closeoutAsk'] !== undefined) { 143 | this.closeoutAsk = data['closeoutAsk']; 144 | } 145 | 146 | if (data['quoteHomeConversionFactors'] !== undefined) { 147 | this.quoteHomeConversionFactors = new QuoteHomeConversionFactors(data['quoteHomeConversionFactors']); 148 | } 149 | 150 | if (data['unitsAvailable'] !== undefined) { 151 | this.unitsAvailable = new order.UnitsAvailable(data['unitsAvailable']); 152 | } 153 | 154 | } 155 | } 156 | 157 | const QuoteHomeConversionFactors_Properties = [ 158 | new Property( 159 | 'positiveUnits', 160 | "Positive Units", 161 | "The factor used to convert a positive amount of the Price's Instrument's quote currency into a positive amount of the Account's home currency. Conversion is performed by multiplying the quote units by the conversion factor.", 162 | 'primitive', 163 | 'primitives.DecimalNumber' 164 | ), 165 | new Property( 166 | 'negativeUnits', 167 | "Negative Units", 168 | "The factor used to convert a negative amount of the Price's Instrument's quote currency into a negative amount of the Account's home currency. Conversion is performed by multiplying the quote units by the conversion factor.", 169 | 'primitive', 170 | 'primitives.DecimalNumber' 171 | ), 172 | ]; 173 | 174 | class QuoteHomeConversionFactors extends Definition { 175 | constructor(data) { 176 | super(); 177 | 178 | this._summaryFormat = ""; 179 | 180 | this._nameFormat = ""; 181 | 182 | this._properties = QuoteHomeConversionFactors_Properties; 183 | 184 | data = data || {}; 185 | 186 | if (data['positiveUnits'] !== undefined) { 187 | this.positiveUnits = data['positiveUnits']; 188 | } 189 | 190 | if (data['negativeUnits'] !== undefined) { 191 | this.negativeUnits = data['negativeUnits']; 192 | } 193 | 194 | } 195 | } 196 | 197 | const HomeConversions_Properties = [ 198 | new Property( 199 | 'currency', 200 | 'currency', 201 | "The currency to be converted into the home currency.", 202 | 'primitive', 203 | 'primitives.Currency' 204 | ), 205 | new Property( 206 | 'accountGain', 207 | "Account Gain", 208 | "The factor used to convert any gains for an Account in the specified currency into the Account's home currency. This would include positive realized P/L and positive financing amounts. Conversion is performed by multiplying the positive P/L by the conversion factor.", 209 | 'primitive', 210 | 'primitives.DecimalNumber' 211 | ), 212 | new Property( 213 | 'accountLoss', 214 | "Account Loss The factor used to convert any losses for an Account in the specified currency into the Account's home currency. This would include negative realized P/L and negative financing amounts. Conversion is performed by multiplying the positive P/L by the conversion factor.", 215 | "The string representation of a decimal number.", 216 | 'primitive', 217 | 'primitives.DecimalNumber' 218 | ), 219 | new Property( 220 | 'positionValue', 221 | "Position Value", 222 | "The factor used to convert a Position or Trade Value in the specified currency into the Account's home currency. Conversion is performed by multiplying the Position or Trade Value by the conversion factor.", 223 | 'primitive', 224 | 'primitives.DecimalNumber' 225 | ), 226 | ]; 227 | 228 | class HomeConversions extends Definition { 229 | constructor(data) { 230 | super(); 231 | 232 | this._summaryFormat = ""; 233 | 234 | this._nameFormat = ""; 235 | 236 | this._properties = HomeConversions_Properties; 237 | 238 | data = data || {}; 239 | 240 | if (data['currency'] !== undefined) { 241 | this.currency = data['currency']; 242 | } 243 | 244 | if (data['accountGain'] !== undefined) { 245 | this.accountGain = data['accountGain']; 246 | } 247 | 248 | if (data['accountLoss'] !== undefined) { 249 | this.accountLoss = data['accountLoss']; 250 | } 251 | 252 | if (data['positionValue'] !== undefined) { 253 | this.positionValue = data['positionValue']; 254 | } 255 | 256 | } 257 | } 258 | 259 | const PricingHeartbeat_Properties = [ 260 | new Property( 261 | 'type', 262 | "Type", 263 | "The string \"HEARTBEAT\"", 264 | 'primitive', 265 | 'string' 266 | ), 267 | new Property( 268 | 'time', 269 | "Time", 270 | "The date/time when the Heartbeat was created.", 271 | 'primitive', 272 | 'primitives.DateTime' 273 | ), 274 | ]; 275 | 276 | class PricingHeartbeat extends Definition { 277 | constructor(data) { 278 | super(); 279 | 280 | this._summaryFormat = "Pricing Heartbeat {time}"; 281 | 282 | this._nameFormat = ""; 283 | 284 | this._properties = PricingHeartbeat_Properties; 285 | 286 | data = data || {}; 287 | 288 | if (data['type'] !== undefined) { 289 | this.type = data['type']; 290 | } 291 | else { 292 | this.type = "HEARTBEAT"; 293 | } 294 | 295 | if (data['time'] !== undefined) { 296 | this.time = data['time']; 297 | } 298 | 299 | } 300 | } 301 | 302 | class EntitySpec { 303 | constructor(context) { 304 | this.context = context; 305 | this.ClientPrice = ClientPrice; 306 | this.QuoteHomeConversionFactors = QuoteHomeConversionFactors; 307 | this.HomeConversions = HomeConversions; 308 | this.PricingHeartbeat = PricingHeartbeat; 309 | } 310 | 311 | basePrices( 312 | queryParams, 313 | responseHandler 314 | ) 315 | { 316 | if (!responseHandler) 317 | { 318 | throw "No responseHandler provided for API call" 319 | } 320 | 321 | 322 | let path = '/v3/pricing'; 323 | 324 | queryParams = queryParams || {}; 325 | 326 | 327 | path = path + "?"; 328 | if (typeof queryParams['time'] !== 'undefined') { 329 | path = path + "time=" + queryParams['time'] + "&"; 330 | } 331 | 332 | let body = {}; 333 | 334 | let handleResponse = (response) => { 335 | if (response.contentType.startsWith("application/json")) 336 | { 337 | let msg = JSON.parse(response.rawBody); 338 | 339 | response.body = {}; 340 | 341 | if (response.statusCode == 200) 342 | { 343 | if (msg['prices'] !== undefined) { 344 | response.body.prices = msg['prices'].map(x => new pricing_common.Price(x)); 345 | } 346 | 347 | } 348 | else if (response.statusCode == 400) 349 | { 350 | } 351 | else if (response.statusCode == 401) 352 | { 353 | } 354 | else if (response.statusCode == 404) 355 | { 356 | } 357 | else if (response.statusCode == 405) 358 | { 359 | } 360 | // 361 | // Assume standard error response with errorCode and errorMessage 362 | // 363 | else 364 | { 365 | if (msg['errorCode'] !== undefined) { 366 | response.body.errorCode = msg['errorCode']; 367 | } 368 | 369 | if (msg['errorMessage'] !== undefined) { 370 | response.body.errorMessage = msg['errorMessage']; 371 | } 372 | } 373 | } 374 | 375 | responseHandler(response); 376 | }; 377 | 378 | 379 | this.context.request( 380 | 'GET', 381 | path, 382 | body, 383 | undefined, 384 | handleResponse 385 | ); 386 | } 387 | 388 | getPriceRange( 389 | instrument, 390 | queryParams, 391 | responseHandler 392 | ) 393 | { 394 | if (!responseHandler) 395 | { 396 | throw "No responseHandler provided for API call" 397 | } 398 | 399 | 400 | let path = '/v3/pricing/range'; 401 | 402 | queryParams = queryParams || {}; 403 | 404 | path = path.replace('{' + 'instrument' + '}', instrument); 405 | 406 | path = path + "?"; 407 | if (typeof queryParams['from'] !== 'undefined') { 408 | path = path + "from=" + queryParams['from'] + "&"; 409 | } 410 | if (typeof queryParams['to'] !== 'undefined') { 411 | path = path + "to=" + queryParams['to'] + "&"; 412 | } 413 | 414 | let body = {}; 415 | 416 | let handleResponse = (response) => { 417 | if (response.contentType.startsWith("application/json")) 418 | { 419 | let msg = JSON.parse(response.rawBody); 420 | 421 | response.body = {}; 422 | 423 | if (response.statusCode == 200) 424 | { 425 | if (msg['prices'] !== undefined) { 426 | response.body.prices = msg['prices'].map(x => new pricing_common.Price(x)); 427 | } 428 | 429 | } 430 | else if (response.statusCode == 400) 431 | { 432 | } 433 | else if (response.statusCode == 401) 434 | { 435 | } 436 | else if (response.statusCode == 404) 437 | { 438 | } 439 | else if (response.statusCode == 405) 440 | { 441 | } 442 | // 443 | // Assume standard error response with errorCode and errorMessage 444 | // 445 | else 446 | { 447 | if (msg['errorCode'] !== undefined) { 448 | response.body.errorCode = msg['errorCode']; 449 | } 450 | 451 | if (msg['errorMessage'] !== undefined) { 452 | response.body.errorMessage = msg['errorMessage']; 453 | } 454 | } 455 | } 456 | 457 | responseHandler(response); 458 | }; 459 | 460 | 461 | this.context.request( 462 | 'GET', 463 | path, 464 | body, 465 | undefined, 466 | handleResponse 467 | ); 468 | } 469 | 470 | get( 471 | accountID, 472 | queryParams, 473 | responseHandler 474 | ) 475 | { 476 | if (!responseHandler) 477 | { 478 | throw "No responseHandler provided for API call" 479 | } 480 | 481 | 482 | let path = '/v3/accounts/{accountID}/pricing'; 483 | 484 | queryParams = queryParams || {}; 485 | 486 | path = path.replace('{' + 'accountID' + '}', accountID); 487 | 488 | path = path + "?"; 489 | if (typeof queryParams['instruments'] !== 'undefined') { 490 | path = path + "instruments=" + queryParams['instruments'] + "&"; 491 | } 492 | if (typeof queryParams['since'] !== 'undefined') { 493 | path = path + "since=" + queryParams['since'] + "&"; 494 | } 495 | if (typeof queryParams['includeUnitsAvailable'] !== 'undefined') { 496 | path = path + "includeUnitsAvailable=" + queryParams['includeUnitsAvailable'] + "&"; 497 | } 498 | if (typeof queryParams['includeHomeConversions'] !== 'undefined') { 499 | path = path + "includeHomeConversions=" + queryParams['includeHomeConversions'] + "&"; 500 | } 501 | 502 | let body = {}; 503 | 504 | let handleResponse = (response) => { 505 | if (response.contentType.startsWith("application/json")) 506 | { 507 | let msg = JSON.parse(response.rawBody); 508 | 509 | response.body = {}; 510 | 511 | if (response.statusCode == 200) 512 | { 513 | if (msg['prices'] !== undefined) { 514 | response.body.prices = msg['prices'].map(x => new ClientPrice(x)); 515 | } 516 | 517 | if (msg['homeConversions'] !== undefined) { 518 | response.body.homeConversions = msg['homeConversions'].map(x => new HomeConversions(x)); 519 | } 520 | 521 | if (msg['time'] !== undefined) { 522 | response.body.time = msg['time']; 523 | } 524 | 525 | } 526 | else if (response.statusCode == 400) 527 | { 528 | } 529 | else if (response.statusCode == 401) 530 | { 531 | } 532 | else if (response.statusCode == 404) 533 | { 534 | } 535 | else if (response.statusCode == 405) 536 | { 537 | } 538 | // 539 | // Assume standard error response with errorCode and errorMessage 540 | // 541 | else 542 | { 543 | if (msg['errorCode'] !== undefined) { 544 | response.body.errorCode = msg['errorCode']; 545 | } 546 | 547 | if (msg['errorMessage'] !== undefined) { 548 | response.body.errorMessage = msg['errorMessage']; 549 | } 550 | } 551 | } 552 | 553 | responseHandler(response); 554 | }; 555 | 556 | 557 | this.context.request( 558 | 'GET', 559 | path, 560 | body, 561 | undefined, 562 | handleResponse 563 | ); 564 | } 565 | 566 | stream( 567 | accountID, 568 | queryParams, 569 | streamChunkHandler, 570 | responseHandler 571 | ) 572 | { 573 | if (!responseHandler) 574 | { 575 | throw "No responseHandler provided for API call" 576 | } 577 | 578 | if (!streamChunkHandler) 579 | { 580 | throw "No streamChunkHandler provided for streaming API call" 581 | } 582 | 583 | let path = '/v3/accounts/{accountID}/pricing/stream'; 584 | 585 | queryParams = queryParams || {}; 586 | 587 | path = path.replace('{' + 'accountID' + '}', accountID); 588 | 589 | path = path + "?"; 590 | if (typeof queryParams['instruments'] !== 'undefined') { 591 | path = path + "instruments=" + queryParams['instruments'] + "&"; 592 | } 593 | if (typeof queryParams['snapshot'] !== 'undefined') { 594 | path = path + "snapshot=" + queryParams['snapshot'] + "&"; 595 | } 596 | 597 | let body = {}; 598 | 599 | let handleResponse = (response) => { 600 | if (response.contentType.startsWith("application/json")) 601 | { 602 | let msg = JSON.parse(response.rawBody); 603 | 604 | response.body = {}; 605 | 606 | if (response.statusCode == 200) 607 | { 608 | if (msg['price'] !== undefined) { 609 | response.body.price = new ClientPrice(msg['price']); 610 | } 611 | 612 | if (msg['heartbeat'] !== undefined) { 613 | response.body.heartbeat = new PricingHeartbeat(msg['heartbeat']); 614 | } 615 | 616 | } 617 | else if (response.statusCode == 400) 618 | { 619 | } 620 | else if (response.statusCode == 401) 621 | { 622 | } 623 | else if (response.statusCode == 404) 624 | { 625 | } 626 | else if (response.statusCode == 405) 627 | { 628 | } 629 | // 630 | // Assume standard error response with errorCode and errorMessage 631 | // 632 | else 633 | { 634 | if (msg['errorCode'] !== undefined) { 635 | response.body.errorCode = msg['errorCode']; 636 | } 637 | 638 | if (msg['errorMessage'] !== undefined) { 639 | response.body.errorMessage = msg['errorMessage']; 640 | } 641 | } 642 | } 643 | 644 | responseHandler(response); 645 | }; 646 | 647 | function generateStreamParser(streamChunkHandler) 648 | { 649 | return (chunk) => { 650 | let msg = JSON.parse(chunk); 651 | 652 | if (msg.type == "HEARTBEAT") 653 | { 654 | streamChunkHandler(new PricingHeartbeat(msg)); 655 | } 656 | else if (msg.type == "PRICE") 657 | { 658 | streamChunkHandler(new Price(msg)); 659 | } 660 | } 661 | } 662 | 663 | this.context.request( 664 | 'GET', 665 | path, 666 | body, 667 | generateStreamParser(streamChunkHandler), 668 | handleResponse 669 | ); 670 | } 671 | 672 | candles( 673 | instrument, 674 | queryParams, 675 | responseHandler 676 | ) 677 | { 678 | if (!responseHandler) 679 | { 680 | throw "No responseHandler provided for API call" 681 | } 682 | 683 | 684 | let path = '/v3/accounts/{accountID}/instruments/{instrument}/candles'; 685 | 686 | queryParams = queryParams || {}; 687 | 688 | path = path.replace('{' + 'instrument' + '}', instrument); 689 | 690 | path = path + "?"; 691 | if (typeof queryParams['price'] !== 'undefined') { 692 | path = path + "price=" + queryParams['price'] + "&"; 693 | } 694 | if (typeof queryParams['granularity'] !== 'undefined') { 695 | path = path + "granularity=" + queryParams['granularity'] + "&"; 696 | } 697 | if (typeof queryParams['count'] !== 'undefined') { 698 | path = path + "count=" + queryParams['count'] + "&"; 699 | } 700 | if (typeof queryParams['from'] !== 'undefined') { 701 | path = path + "from=" + queryParams['from'] + "&"; 702 | } 703 | if (typeof queryParams['to'] !== 'undefined') { 704 | path = path + "to=" + queryParams['to'] + "&"; 705 | } 706 | if (typeof queryParams['smooth'] !== 'undefined') { 707 | path = path + "smooth=" + queryParams['smooth'] + "&"; 708 | } 709 | if (typeof queryParams['includeFirst'] !== 'undefined') { 710 | path = path + "includeFirst=" + queryParams['includeFirst'] + "&"; 711 | } 712 | if (typeof queryParams['dailyAlignment'] !== 'undefined') { 713 | path = path + "dailyAlignment=" + queryParams['dailyAlignment'] + "&"; 714 | } 715 | if (typeof queryParams['alignmentTimezone'] !== 'undefined') { 716 | path = path + "alignmentTimezone=" + queryParams['alignmentTimezone'] + "&"; 717 | } 718 | if (typeof queryParams['weeklyAlignment'] !== 'undefined') { 719 | path = path + "weeklyAlignment=" + queryParams['weeklyAlignment'] + "&"; 720 | } 721 | if (typeof queryParams['units'] !== 'undefined') { 722 | path = path + "units=" + queryParams['units'] + "&"; 723 | } 724 | 725 | let body = {}; 726 | 727 | let handleResponse = (response) => { 728 | if (response.contentType.startsWith("application/json")) 729 | { 730 | let msg = JSON.parse(response.rawBody); 731 | 732 | response.body = {}; 733 | 734 | if (response.statusCode == 200) 735 | { 736 | if (msg['instrument'] !== undefined) { 737 | response.body.instrument = msg['instrument']; 738 | } 739 | 740 | if (msg['granularity'] !== undefined) { 741 | response.body.granularity = msg['granularity']; 742 | } 743 | 744 | if (msg['candles'] !== undefined) { 745 | response.body.candles = msg['candles'].map(x => new instrument.Candlestick(x)); 746 | } 747 | 748 | } 749 | else if (response.statusCode == 400) 750 | { 751 | } 752 | else if (response.statusCode == 401) 753 | { 754 | } 755 | else if (response.statusCode == 404) 756 | { 757 | } 758 | else if (response.statusCode == 405) 759 | { 760 | } 761 | // 762 | // Assume standard error response with errorCode and errorMessage 763 | // 764 | else 765 | { 766 | if (msg['errorCode'] !== undefined) { 767 | response.body.errorCode = msg['errorCode']; 768 | } 769 | 770 | if (msg['errorMessage'] !== undefined) { 771 | response.body.errorMessage = msg['errorMessage']; 772 | } 773 | } 774 | } 775 | 776 | responseHandler(response); 777 | }; 778 | 779 | 780 | this.context.request( 781 | 'GET', 782 | path, 783 | body, 784 | undefined, 785 | handleResponse 786 | ); 787 | } 788 | 789 | 790 | 791 | } 792 | 793 | exports.ClientPrice = ClientPrice; 794 | exports.QuoteHomeConversionFactors = QuoteHomeConversionFactors; 795 | exports.HomeConversions = HomeConversions; 796 | exports.PricingHeartbeat = PricingHeartbeat; 797 | 798 | exports.EntitySpec = EntitySpec; 799 | -------------------------------------------------------------------------------- /src/pricing_common.js: -------------------------------------------------------------------------------- 1 | /* jshint esversion: 6 */ 2 | 3 | "use strict"; 4 | 5 | var Definition = require('./base').Definition; 6 | var Property = require('./base').Property; 7 | var Field = require('./base').Field; 8 | 9 | 10 | 11 | 12 | const PriceBucket_Properties = [ 13 | new Property( 14 | 'price', 15 | "Price", 16 | "The Price offered by the PriceBucket", 17 | 'primitive', 18 | 'pricing_common.PriceValue' 19 | ), 20 | new Property( 21 | 'liquidity', 22 | "Liquidity", 23 | "The amount of liquidity offered by the PriceBucket", 24 | 'primitive', 25 | 'integer' 26 | ), 27 | ]; 28 | 29 | class PriceBucket extends Definition { 30 | constructor(data) { 31 | super(); 32 | 33 | this._summaryFormat = ""; 34 | 35 | this._nameFormat = ""; 36 | 37 | this._properties = PriceBucket_Properties; 38 | 39 | data = data || {}; 40 | 41 | if (data['price'] !== undefined) { 42 | this.price = data['price']; 43 | } 44 | 45 | if (data['liquidity'] !== undefined) { 46 | this.liquidity = data['liquidity']; 47 | } 48 | 49 | } 50 | } 51 | 52 | const Price_Properties = [ 53 | new Property( 54 | 'instrument', 55 | "Instrument", 56 | "The Price's Instrument.", 57 | 'primitive', 58 | 'primitives.InstrumentName' 59 | ), 60 | new Property( 61 | 'tradeable', 62 | "Is Tradeable", 63 | "Flag indicating if the Price is tradeable or not", 64 | 'primitive', 65 | 'boolean' 66 | ), 67 | new Property( 68 | 'timestamp', 69 | "Timestamp", 70 | "The date/time when the Price was created.", 71 | 'primitive', 72 | 'primitives.DateTime' 73 | ), 74 | new Property( 75 | 'baseBid', 76 | "Base Bid", 77 | "The base bid price as calculated by pricing.", 78 | 'primitive', 79 | 'pricing_common.PriceValue' 80 | ), 81 | new Property( 82 | 'baseAsk', 83 | "Base Ask", 84 | "The base ask price as calculated by pricing.", 85 | 'primitive', 86 | 'pricing_common.PriceValue' 87 | ), 88 | new Property( 89 | 'bids', 90 | "Bids", 91 | "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.", 92 | 'array_object', 93 | 'PriceBucket' 94 | ), 95 | new Property( 96 | 'asks', 97 | "Asks", 98 | "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.", 99 | 'array_object', 100 | 'PriceBucket' 101 | ), 102 | new Property( 103 | 'closeoutBid', 104 | "Closeout Bid", 105 | "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.", 106 | 'primitive', 107 | 'pricing_common.PriceValue' 108 | ), 109 | new Property( 110 | 'closeoutAsk', 111 | "Closeout Ask", 112 | "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.", 113 | 'primitive', 114 | 'pricing_common.PriceValue' 115 | ), 116 | ]; 117 | 118 | class Price extends Definition { 119 | constructor(data) { 120 | super(); 121 | 122 | this._summaryFormat = ""; 123 | 124 | this._nameFormat = ""; 125 | 126 | this._properties = Price_Properties; 127 | 128 | data = data || {}; 129 | 130 | if (data['instrument'] !== undefined) { 131 | this.instrument = data['instrument']; 132 | } 133 | 134 | if (data['tradeable'] !== undefined) { 135 | this.tradeable = data['tradeable']; 136 | } 137 | 138 | if (data['timestamp'] !== undefined) { 139 | this.timestamp = data['timestamp']; 140 | } 141 | 142 | if (data['baseBid'] !== undefined) { 143 | this.baseBid = data['baseBid']; 144 | } 145 | 146 | if (data['baseAsk'] !== undefined) { 147 | this.baseAsk = data['baseAsk']; 148 | } 149 | 150 | if (data['bids'] !== undefined) { 151 | this.bids = data['bids'].map(x => new PriceBucket(x)); 152 | } 153 | 154 | if (data['asks'] !== undefined) { 155 | this.asks = data['asks'].map(x => new PriceBucket(x)); 156 | } 157 | 158 | if (data['closeoutBid'] !== undefined) { 159 | this.closeoutBid = data['closeoutBid']; 160 | } 161 | 162 | if (data['closeoutAsk'] !== undefined) { 163 | this.closeoutAsk = data['closeoutAsk']; 164 | } 165 | 166 | } 167 | } 168 | 169 | class EntitySpec { 170 | constructor(context) { 171 | this.context = context; 172 | this.PriceBucket = PriceBucket; 173 | this.Price = Price; 174 | } 175 | 176 | 177 | 178 | } 179 | 180 | exports.PriceBucket = PriceBucket; 181 | exports.Price = Price; 182 | 183 | exports.EntitySpec = EntitySpec; 184 | -------------------------------------------------------------------------------- /src/primitives.js: -------------------------------------------------------------------------------- 1 | /* jshint esversion: 6 */ 2 | 3 | "use strict"; 4 | 5 | var Definition = require('./base').Definition; 6 | var Property = require('./base').Property; 7 | var Field = require('./base').Field; 8 | 9 | 10 | 11 | 12 | const Instrument_Properties = [ 13 | new Property( 14 | 'name', 15 | 'name', 16 | "The name of the Instrument", 17 | 'primitive', 18 | 'primitives.InstrumentName' 19 | ), 20 | new Property( 21 | 'type', 22 | 'type', 23 | "The type of the Instrument", 24 | 'primitive', 25 | 'primitives.InstrumentType' 26 | ), 27 | new Property( 28 | 'displayName', 29 | 'displayName', 30 | "The display name of the Instrument", 31 | 'primitive', 32 | 'string' 33 | ), 34 | new Property( 35 | 'pipLocation', 36 | 'pipLocation', 37 | "The location of the \"pip\" for this instrument. The decimal position of the pip in this Instrument's price can be found at 10 ^ pipLocation (e.g. -4 pipLocation results in a decimal pip position of 10 ^ -4 = 0.0001).", 38 | 'primitive', 39 | 'integer' 40 | ), 41 | new Property( 42 | 'displayPrecision', 43 | 'displayPrecision', 44 | "The number of decimal places that should be used to display prices for this instrument. (e.g. a displayPrecision of 5 would result in a price of \"1\" being displayed as \"1.00000\")", 45 | 'primitive', 46 | 'integer' 47 | ), 48 | new Property( 49 | 'tradeUnitsPrecision', 50 | 'tradeUnitsPrecision', 51 | "The amount of decimal places that may be provided when specifying the number of units traded for this instrument.", 52 | 'primitive', 53 | 'integer' 54 | ), 55 | new Property( 56 | 'minimumTradeSize', 57 | 'minimumTradeSize', 58 | "The smallest number of units allowed to be traded for this instrument.", 59 | 'primitive', 60 | 'primitives.DecimalNumber' 61 | ), 62 | new Property( 63 | 'maximumTrailingStopDistance', 64 | 'maximumTrailingStopDistance', 65 | "The maximum trailing stop distance allowed for a trailing stop loss created for this instrument. Specified in price units.", 66 | 'primitive', 67 | 'primitives.DecimalNumber' 68 | ), 69 | new Property( 70 | 'minimumTrailingStopDistance', 71 | 'minimumTrailingStopDistance', 72 | "The minimum trailing stop distance allowed for a trailing stop loss created for this instrument. Specified in price units.", 73 | 'primitive', 74 | 'primitives.DecimalNumber' 75 | ), 76 | new Property( 77 | 'maximumPositionSize', 78 | 'maximumPositionSize', 79 | "The maximum position size allowed for this instrument. Specified in units.", 80 | 'primitive', 81 | 'primitives.DecimalNumber' 82 | ), 83 | new Property( 84 | 'maximumOrderUnits', 85 | 'maximumOrderUnits', 86 | "The maximum units allowed for an Order placed for this instrument. Specified in units.", 87 | 'primitive', 88 | 'primitives.DecimalNumber' 89 | ), 90 | new Property( 91 | 'marginRate', 92 | 'marginRate', 93 | "The margin rate for this instrument.", 94 | 'primitive', 95 | 'primitives.DecimalNumber' 96 | ), 97 | new Property( 98 | 'commission', 99 | 'commission', 100 | "The commission structure for this instrument.", 101 | 'object', 102 | 'primitives.InstrumentCommission' 103 | ), 104 | ]; 105 | 106 | class Instrument extends Definition { 107 | constructor(data) { 108 | super(); 109 | 110 | this._summaryFormat = ""; 111 | 112 | this._nameFormat = ""; 113 | 114 | this._properties = Instrument_Properties; 115 | 116 | data = data || {}; 117 | 118 | if (data['name'] !== undefined) { 119 | this.name = data['name']; 120 | } 121 | 122 | if (data['type'] !== undefined) { 123 | this.type = data['type']; 124 | } 125 | 126 | if (data['displayName'] !== undefined) { 127 | this.displayName = data['displayName']; 128 | } 129 | 130 | if (data['pipLocation'] !== undefined) { 131 | this.pipLocation = data['pipLocation']; 132 | } 133 | 134 | if (data['displayPrecision'] !== undefined) { 135 | this.displayPrecision = data['displayPrecision']; 136 | } 137 | 138 | if (data['tradeUnitsPrecision'] !== undefined) { 139 | this.tradeUnitsPrecision = data['tradeUnitsPrecision']; 140 | } 141 | 142 | if (data['minimumTradeSize'] !== undefined) { 143 | this.minimumTradeSize = data['minimumTradeSize']; 144 | } 145 | 146 | if (data['maximumTrailingStopDistance'] !== undefined) { 147 | this.maximumTrailingStopDistance = data['maximumTrailingStopDistance']; 148 | } 149 | 150 | if (data['minimumTrailingStopDistance'] !== undefined) { 151 | this.minimumTrailingStopDistance = data['minimumTrailingStopDistance']; 152 | } 153 | 154 | if (data['maximumPositionSize'] !== undefined) { 155 | this.maximumPositionSize = data['maximumPositionSize']; 156 | } 157 | 158 | if (data['maximumOrderUnits'] !== undefined) { 159 | this.maximumOrderUnits = data['maximumOrderUnits']; 160 | } 161 | 162 | if (data['marginRate'] !== undefined) { 163 | this.marginRate = data['marginRate']; 164 | } 165 | 166 | if (data['commission'] !== undefined) { 167 | this.commission = new InstrumentCommission(data['commission']); 168 | } 169 | 170 | } 171 | } 172 | 173 | const InstrumentCommission_Properties = [ 174 | new Property( 175 | 'commission', 176 | 'commission', 177 | "The commission amount (in the Account's home currency) charged per unitsTraded of the instrument", 178 | 'primitive', 179 | 'primitives.DecimalNumber' 180 | ), 181 | new Property( 182 | 'unitsTraded', 183 | 'unitsTraded', 184 | "The number of units traded that the commission amount is based on.", 185 | 'primitive', 186 | 'primitives.DecimalNumber' 187 | ), 188 | new Property( 189 | 'minimumCommission', 190 | 'minimumCommission', 191 | "The minimum commission amount (in the Account's home currency) that is charged when an Order is filled for this instrument.", 192 | 'primitive', 193 | 'primitives.DecimalNumber' 194 | ), 195 | ]; 196 | 197 | class InstrumentCommission extends Definition { 198 | constructor(data) { 199 | super(); 200 | 201 | this._summaryFormat = ""; 202 | 203 | this._nameFormat = ""; 204 | 205 | this._properties = InstrumentCommission_Properties; 206 | 207 | data = data || {}; 208 | 209 | if (data['commission'] !== undefined) { 210 | this.commission = data['commission']; 211 | } 212 | 213 | if (data['unitsTraded'] !== undefined) { 214 | this.unitsTraded = data['unitsTraded']; 215 | } 216 | 217 | if (data['minimumCommission'] !== undefined) { 218 | this.minimumCommission = data['minimumCommission']; 219 | } 220 | 221 | } 222 | } 223 | 224 | const GuaranteedStopLossOrderLevelRestriction_Properties = [ 225 | new Property( 226 | 'volume', 227 | 'volume', 228 | "Applies to Trades with a guaranteed Stop Loss Order attached for the specified Instrument. This is the total allowed Trade volume that can exist within the priceRange based on the trigger prices of the guaranteed Stop Loss Orders.", 229 | 'primitive', 230 | 'primitives.DecimalNumber' 231 | ), 232 | new Property( 233 | 'priceRange', 234 | 'priceRange', 235 | "The price range the volume applies to. This value is in price units.", 236 | 'primitive', 237 | 'primitives.DecimalNumber' 238 | ), 239 | ]; 240 | 241 | class GuaranteedStopLossOrderLevelRestriction extends Definition { 242 | constructor(data) { 243 | super(); 244 | 245 | this._summaryFormat = ""; 246 | 247 | this._nameFormat = ""; 248 | 249 | this._properties = GuaranteedStopLossOrderLevelRestriction_Properties; 250 | 251 | data = data || {}; 252 | 253 | if (data['volume'] !== undefined) { 254 | this.volume = data['volume']; 255 | } 256 | 257 | if (data['priceRange'] !== undefined) { 258 | this.priceRange = data['priceRange']; 259 | } 260 | 261 | } 262 | } 263 | 264 | class EntitySpec { 265 | constructor(context) { 266 | this.context = context; 267 | this.Instrument = Instrument; 268 | this.InstrumentCommission = InstrumentCommission; 269 | this.GuaranteedStopLossOrderLevelRestriction = GuaranteedStopLossOrderLevelRestriction; 270 | } 271 | 272 | 273 | 274 | } 275 | 276 | exports.Instrument = Instrument; 277 | exports.InstrumentCommission = InstrumentCommission; 278 | exports.GuaranteedStopLossOrderLevelRestriction = GuaranteedStopLossOrderLevelRestriction; 279 | 280 | exports.EntitySpec = EntitySpec; 281 | -------------------------------------------------------------------------------- /src/site.js: -------------------------------------------------------------------------------- 1 | /* jshint esversion: 6 */ 2 | 3 | "use strict"; 4 | 5 | var Definition = require('./base').Definition; 6 | var Property = require('./base').Property; 7 | var Field = require('./base').Field; 8 | 9 | 10 | 11 | 12 | const MT4TransactionHeartbeat_Properties = [ 13 | new Property( 14 | 'type', 15 | 'type', 16 | "The string \"HEARTBEAT\"", 17 | 'primitive', 18 | 'string' 19 | ), 20 | new Property( 21 | 'time', 22 | 'time', 23 | "The date/time when the TransactionHeartbeat was created.", 24 | 'primitive', 25 | 'primitives.DateTime' 26 | ), 27 | ]; 28 | 29 | class MT4TransactionHeartbeat extends Definition { 30 | constructor(data) { 31 | super(); 32 | 33 | this._summaryFormat = "Transaction Heartbeat {time}"; 34 | 35 | this._nameFormat = ""; 36 | 37 | this._properties = MT4TransactionHeartbeat_Properties; 38 | 39 | data = data || {}; 40 | 41 | if (data['type'] !== undefined) { 42 | this.type = data['type']; 43 | } 44 | else { 45 | this.type = "HEARTBEAT"; 46 | } 47 | 48 | if (data['time'] !== undefined) { 49 | this.time = data['time']; 50 | } 51 | 52 | } 53 | } 54 | 55 | class EntitySpec { 56 | constructor(context) { 57 | this.context = context; 58 | this.MT4TransactionHeartbeat = MT4TransactionHeartbeat; 59 | } 60 | 61 | 62 | 63 | } 64 | 65 | exports.MT4TransactionHeartbeat = MT4TransactionHeartbeat; 66 | 67 | exports.EntitySpec = EntitySpec; 68 | -------------------------------------------------------------------------------- /src/trade.js: -------------------------------------------------------------------------------- 1 | /* jshint esversion: 6 */ 2 | 3 | "use strict"; 4 | 5 | var Definition = require('./base').Definition; 6 | var Property = require('./base').Property; 7 | var Field = require('./base').Field; 8 | 9 | var transaction = require('./transaction'); 10 | var order = require('./order'); 11 | 12 | 13 | 14 | const Trade_Properties = [ 15 | new Property( 16 | 'id', 17 | "Trade ID", 18 | "The Trade's identifier, unique within the Trade's Account.", 19 | 'primitive', 20 | 'trade.TradeID' 21 | ), 22 | new Property( 23 | 'instrument', 24 | "Instrument", 25 | "The Trade's Instrument.", 26 | 'primitive', 27 | 'primitives.InstrumentName' 28 | ), 29 | new Property( 30 | 'price', 31 | "Fill Price", 32 | "The execution price of the Trade.", 33 | 'primitive', 34 | 'pricing_common.PriceValue' 35 | ), 36 | new Property( 37 | 'openTime', 38 | "Open Time", 39 | "The date/time when the Trade was opened.", 40 | 'primitive', 41 | 'primitives.DateTime' 42 | ), 43 | new Property( 44 | 'state', 45 | "State", 46 | "The current state of the Trade.", 47 | 'primitive', 48 | 'trade.TradeState' 49 | ), 50 | new Property( 51 | 'initialUnits', 52 | "Initial Trade Units", 53 | "The initial size of the Trade. Negative values indicate a short Trade, and positive values indicate a long Trade.", 54 | 'primitive', 55 | 'primitives.DecimalNumber' 56 | ), 57 | new Property( 58 | 'initialMarginRequired', 59 | "Initial Margin Required", 60 | "The margin required at the time the Trade was created. Note, this is the 'pure' margin required, it is not the 'effective' margin used that factors in the trade risk if a GSLO is attached to the trade.", 61 | 'primitive', 62 | 'primitives.AccountUnits' 63 | ), 64 | new Property( 65 | 'currentUnits', 66 | "Current Open Trade Units", 67 | "The number of units currently open for the Trade. This value is reduced to 0.0 as the Trade is closed.", 68 | 'primitive', 69 | 'primitives.DecimalNumber' 70 | ), 71 | new Property( 72 | 'realizedPL', 73 | "Realized Profit/Loss", 74 | "The total profit/loss realized on the closed portion of the Trade.", 75 | 'primitive', 76 | 'primitives.AccountUnits' 77 | ), 78 | new Property( 79 | 'unrealizedPL', 80 | "Unrealized Profit/Loss", 81 | "The unrealized profit/loss on the open portion of the Trade.", 82 | 'primitive', 83 | 'primitives.AccountUnits' 84 | ), 85 | new Property( 86 | 'marginUsed', 87 | "Margin Used", 88 | "Margin currently used by the Trade.", 89 | 'primitive', 90 | 'primitives.AccountUnits' 91 | ), 92 | new Property( 93 | 'averageClosePrice', 94 | "Average Close Price", 95 | "The average closing price of the Trade. Only present if the Trade has been closed or reduced at least once.", 96 | 'primitive', 97 | 'pricing_common.PriceValue' 98 | ), 99 | new Property( 100 | 'closingTransactionIDs', 101 | "Closing Transaction IDs", 102 | "The IDs of the Transactions that have closed portions of this Trade.", 103 | 'array_primitive', 104 | 'TransactionID' 105 | ), 106 | new Property( 107 | 'financing', 108 | "Financing", 109 | "The financing paid/collected for this Trade.", 110 | 'primitive', 111 | 'primitives.AccountUnits' 112 | ), 113 | new Property( 114 | 'closeTime', 115 | "Close Time", 116 | "The date/time when the Trade was fully closed. Only provided for Trades whose state is CLOSED.", 117 | 'primitive', 118 | 'primitives.DateTime' 119 | ), 120 | new Property( 121 | 'clientExtensions', 122 | "Client Extensions", 123 | "The client extensions of the Trade.", 124 | 'object', 125 | 'transaction.ClientExtensions' 126 | ), 127 | new Property( 128 | 'takeProfitOrder', 129 | "Take Profit Order", 130 | "Full representation of the Trade's Take Profit Order, only provided if such an Order exists.", 131 | 'object', 132 | 'order.TakeProfitOrder' 133 | ), 134 | new Property( 135 | 'stopLossOrder', 136 | "Stop Loss Order", 137 | "Full representation of the Trade's Stop Loss Order, only provided if such an Order exists.", 138 | 'object', 139 | 'order.StopLossOrder' 140 | ), 141 | new Property( 142 | 'trailingStopLossOrder', 143 | "Trailing Stop Loss Order", 144 | "Full representation of the Trade's Trailing Stop Loss Order, only provided if such an Order exists.", 145 | 'object', 146 | 'order.TrailingStopLossOrder' 147 | ), 148 | ]; 149 | 150 | class Trade extends Definition { 151 | constructor(data) { 152 | super(); 153 | 154 | this._summaryFormat = "{currentUnits} ({initialUnits}) of {instrument} @ {price}"; 155 | 156 | this._nameFormat = "Trade {id}"; 157 | 158 | this._properties = Trade_Properties; 159 | 160 | data = data || {}; 161 | 162 | if (data['id'] !== undefined) { 163 | this.id = data['id']; 164 | } 165 | 166 | if (data['instrument'] !== undefined) { 167 | this.instrument = data['instrument']; 168 | } 169 | 170 | if (data['price'] !== undefined) { 171 | this.price = data['price']; 172 | } 173 | 174 | if (data['openTime'] !== undefined) { 175 | this.openTime = data['openTime']; 176 | } 177 | 178 | if (data['state'] !== undefined) { 179 | this.state = data['state']; 180 | } 181 | 182 | if (data['initialUnits'] !== undefined) { 183 | this.initialUnits = data['initialUnits']; 184 | } 185 | 186 | if (data['initialMarginRequired'] !== undefined) { 187 | this.initialMarginRequired = data['initialMarginRequired']; 188 | } 189 | 190 | if (data['currentUnits'] !== undefined) { 191 | this.currentUnits = data['currentUnits']; 192 | } 193 | 194 | if (data['realizedPL'] !== undefined) { 195 | this.realizedPL = data['realizedPL']; 196 | } 197 | 198 | if (data['unrealizedPL'] !== undefined) { 199 | this.unrealizedPL = data['unrealizedPL']; 200 | } 201 | 202 | if (data['marginUsed'] !== undefined) { 203 | this.marginUsed = data['marginUsed']; 204 | } 205 | 206 | if (data['averageClosePrice'] !== undefined) { 207 | this.averageClosePrice = data['averageClosePrice']; 208 | } 209 | 210 | if (data['closingTransactionIDs'] !== undefined) { 211 | this.closingTransactionIDs = data['closingTransactionIDs']; 212 | } 213 | 214 | if (data['financing'] !== undefined) { 215 | this.financing = data['financing']; 216 | } 217 | 218 | if (data['closeTime'] !== undefined) { 219 | this.closeTime = data['closeTime']; 220 | } 221 | 222 | if (data['clientExtensions'] !== undefined) { 223 | this.clientExtensions = new transaction.ClientExtensions(data['clientExtensions']); 224 | } 225 | 226 | if (data['takeProfitOrder'] !== undefined) { 227 | this.takeProfitOrder = new order.TakeProfitOrder(data['takeProfitOrder']); 228 | } 229 | 230 | if (data['stopLossOrder'] !== undefined) { 231 | this.stopLossOrder = new order.StopLossOrder(data['stopLossOrder']); 232 | } 233 | 234 | if (data['trailingStopLossOrder'] !== undefined) { 235 | this.trailingStopLossOrder = new order.TrailingStopLossOrder(data['trailingStopLossOrder']); 236 | } 237 | 238 | } 239 | } 240 | 241 | const TradeSummary_Properties = [ 242 | new Property( 243 | 'id', 244 | "Trade ID", 245 | "The Trade's identifier, unique within the Trade's Account.", 246 | 'primitive', 247 | 'trade.TradeID' 248 | ), 249 | new Property( 250 | 'instrument', 251 | "Instrument", 252 | "The Trade's Instrument.", 253 | 'primitive', 254 | 'primitives.InstrumentName' 255 | ), 256 | new Property( 257 | 'price', 258 | "Fill Price", 259 | "The execution price of the Trade.", 260 | 'primitive', 261 | 'pricing_common.PriceValue' 262 | ), 263 | new Property( 264 | 'openTime', 265 | "Open Time", 266 | "The date/time when the Trade was opened.", 267 | 'primitive', 268 | 'primitives.DateTime' 269 | ), 270 | new Property( 271 | 'state', 272 | "State", 273 | "The current state of the Trade.", 274 | 'primitive', 275 | 'trade.TradeState' 276 | ), 277 | new Property( 278 | 'initialUnits', 279 | "Initial Trade Units", 280 | "The initial size of the Trade. Negative values indicate a short Trade, and positive values indicate a long Trade.", 281 | 'primitive', 282 | 'primitives.DecimalNumber' 283 | ), 284 | new Property( 285 | 'initialMarginRequired', 286 | "Initial Margin Required", 287 | "The margin required at the time the Trade was created. Note, this is the 'pure' margin required, it is not the 'effective' margin used that factors in the trade risk if a GSLO is attached to the trade.", 288 | 'primitive', 289 | 'primitives.AccountUnits' 290 | ), 291 | new Property( 292 | 'currentUnits', 293 | "Current Open Trade Units", 294 | "The number of units currently open for the Trade. This value is reduced to 0.0 as the Trade is closed.", 295 | 'primitive', 296 | 'primitives.DecimalNumber' 297 | ), 298 | new Property( 299 | 'realizedPL', 300 | "Realized Profit/Loss", 301 | "The total profit/loss realized on the closed portion of the Trade.", 302 | 'primitive', 303 | 'primitives.AccountUnits' 304 | ), 305 | new Property( 306 | 'unrealizedPL', 307 | "Unrealized Profit/Loss", 308 | "The unrealized profit/loss on the open portion of the Trade.", 309 | 'primitive', 310 | 'primitives.AccountUnits' 311 | ), 312 | new Property( 313 | 'marginUsed', 314 | "Margin Used", 315 | "Margin currently used by the Trade.", 316 | 'primitive', 317 | 'primitives.AccountUnits' 318 | ), 319 | new Property( 320 | 'averageClosePrice', 321 | "Average Close Price", 322 | "The average closing price of the Trade. Only present if the Trade has been closed or reduced at least once.", 323 | 'primitive', 324 | 'pricing_common.PriceValue' 325 | ), 326 | new Property( 327 | 'closingTransactionIDs', 328 | "Closing Transaction IDs", 329 | "The IDs of the Transactions that have closed portions of this Trade.", 330 | 'array_primitive', 331 | 'TransactionID' 332 | ), 333 | new Property( 334 | 'financing', 335 | "Financing", 336 | "The financing paid/collected for this Trade.", 337 | 'primitive', 338 | 'primitives.AccountUnits' 339 | ), 340 | new Property( 341 | 'closeTime', 342 | "Close Time", 343 | "The date/time when the Trade was fully closed. Only provided for Trades whose state is CLOSED.", 344 | 'primitive', 345 | 'primitives.DateTime' 346 | ), 347 | new Property( 348 | 'clientExtensions', 349 | "Client Extensions", 350 | "The client extensions of the Trade.", 351 | 'object', 352 | 'transaction.ClientExtensions' 353 | ), 354 | new Property( 355 | 'takeProfitOrderID', 356 | "Take Profit Order ID", 357 | "ID of the Trade's Take Profit Order, only provided if such an Order exists.", 358 | 'primitive', 359 | 'order.OrderID' 360 | ), 361 | new Property( 362 | 'stopLossOrderID', 363 | "Stop Loss Order ID", 364 | "ID of the Trade's Stop Loss Order, only provided if such an Order exists.", 365 | 'primitive', 366 | 'order.OrderID' 367 | ), 368 | new Property( 369 | 'trailingStopLossOrderID', 370 | "Trailing Stop Loss Order ID", 371 | "ID of the Trade's Trailing Stop Loss Order, only provided if such an Order exists.", 372 | 'primitive', 373 | 'order.OrderID' 374 | ), 375 | ]; 376 | 377 | class TradeSummary extends Definition { 378 | constructor(data) { 379 | super(); 380 | 381 | this._summaryFormat = "{currentUnits} ({initialUnits}) of {instrument} @ {price}"; 382 | 383 | this._nameFormat = "Trade {id}"; 384 | 385 | this._properties = TradeSummary_Properties; 386 | 387 | data = data || {}; 388 | 389 | if (data['id'] !== undefined) { 390 | this.id = data['id']; 391 | } 392 | 393 | if (data['instrument'] !== undefined) { 394 | this.instrument = data['instrument']; 395 | } 396 | 397 | if (data['price'] !== undefined) { 398 | this.price = data['price']; 399 | } 400 | 401 | if (data['openTime'] !== undefined) { 402 | this.openTime = data['openTime']; 403 | } 404 | 405 | if (data['state'] !== undefined) { 406 | this.state = data['state']; 407 | } 408 | 409 | if (data['initialUnits'] !== undefined) { 410 | this.initialUnits = data['initialUnits']; 411 | } 412 | 413 | if (data['initialMarginRequired'] !== undefined) { 414 | this.initialMarginRequired = data['initialMarginRequired']; 415 | } 416 | 417 | if (data['currentUnits'] !== undefined) { 418 | this.currentUnits = data['currentUnits']; 419 | } 420 | 421 | if (data['realizedPL'] !== undefined) { 422 | this.realizedPL = data['realizedPL']; 423 | } 424 | 425 | if (data['unrealizedPL'] !== undefined) { 426 | this.unrealizedPL = data['unrealizedPL']; 427 | } 428 | 429 | if (data['marginUsed'] !== undefined) { 430 | this.marginUsed = data['marginUsed']; 431 | } 432 | 433 | if (data['averageClosePrice'] !== undefined) { 434 | this.averageClosePrice = data['averageClosePrice']; 435 | } 436 | 437 | if (data['closingTransactionIDs'] !== undefined) { 438 | this.closingTransactionIDs = data['closingTransactionIDs']; 439 | } 440 | 441 | if (data['financing'] !== undefined) { 442 | this.financing = data['financing']; 443 | } 444 | 445 | if (data['closeTime'] !== undefined) { 446 | this.closeTime = data['closeTime']; 447 | } 448 | 449 | if (data['clientExtensions'] !== undefined) { 450 | this.clientExtensions = new transaction.ClientExtensions(data['clientExtensions']); 451 | } 452 | 453 | if (data['takeProfitOrderID'] !== undefined) { 454 | this.takeProfitOrderID = data['takeProfitOrderID']; 455 | } 456 | 457 | if (data['stopLossOrderID'] !== undefined) { 458 | this.stopLossOrderID = data['stopLossOrderID']; 459 | } 460 | 461 | if (data['trailingStopLossOrderID'] !== undefined) { 462 | this.trailingStopLossOrderID = data['trailingStopLossOrderID']; 463 | } 464 | 465 | } 466 | } 467 | 468 | const CalculatedTradeState_Properties = [ 469 | new Property( 470 | 'id', 471 | "Trade ID", 472 | "The Trade's ID.", 473 | 'primitive', 474 | 'trade.TradeID' 475 | ), 476 | new Property( 477 | 'unrealizedPL', 478 | "Trade UPL", 479 | "The Trade's unrealized profit/loss.", 480 | 'primitive', 481 | 'primitives.AccountUnits' 482 | ), 483 | new Property( 484 | 'marginUsed', 485 | "Margin Used", 486 | "Margin currently used by the Trade.", 487 | 'primitive', 488 | 'primitives.AccountUnits' 489 | ), 490 | ]; 491 | 492 | class CalculatedTradeState extends Definition { 493 | constructor(data) { 494 | super(); 495 | 496 | this._summaryFormat = ""; 497 | 498 | this._nameFormat = ""; 499 | 500 | this._properties = CalculatedTradeState_Properties; 501 | 502 | data = data || {}; 503 | 504 | if (data['id'] !== undefined) { 505 | this.id = data['id']; 506 | } 507 | 508 | if (data['unrealizedPL'] !== undefined) { 509 | this.unrealizedPL = data['unrealizedPL']; 510 | } 511 | 512 | if (data['marginUsed'] !== undefined) { 513 | this.marginUsed = data['marginUsed']; 514 | } 515 | 516 | } 517 | } 518 | 519 | class EntitySpec { 520 | constructor(context) { 521 | this.context = context; 522 | this.Trade = Trade; 523 | this.TradeSummary = TradeSummary; 524 | this.CalculatedTradeState = CalculatedTradeState; 525 | } 526 | 527 | list( 528 | accountID, 529 | queryParams, 530 | responseHandler 531 | ) 532 | { 533 | if (!responseHandler) 534 | { 535 | throw "No responseHandler provided for API call" 536 | } 537 | 538 | 539 | let path = '/v3/accounts/{accountID}/trades'; 540 | 541 | queryParams = queryParams || {}; 542 | 543 | path = path.replace('{' + 'accountID' + '}', accountID); 544 | 545 | path = path + "?"; 546 | if (typeof queryParams['ids'] !== 'undefined') { 547 | path = path + "ids=" + queryParams['ids'] + "&"; 548 | } 549 | if (typeof queryParams['state'] !== 'undefined') { 550 | path = path + "state=" + queryParams['state'] + "&"; 551 | } 552 | if (typeof queryParams['instrument'] !== 'undefined') { 553 | path = path + "instrument=" + queryParams['instrument'] + "&"; 554 | } 555 | if (typeof queryParams['count'] !== 'undefined') { 556 | path = path + "count=" + queryParams['count'] + "&"; 557 | } 558 | if (typeof queryParams['beforeID'] !== 'undefined') { 559 | path = path + "beforeID=" + queryParams['beforeID'] + "&"; 560 | } 561 | 562 | let body = {}; 563 | 564 | let handleResponse = (response) => { 565 | if (response.contentType.startsWith("application/json")) 566 | { 567 | let msg = JSON.parse(response.rawBody); 568 | 569 | response.body = {}; 570 | 571 | if (response.statusCode == 200) 572 | { 573 | if (msg['trades'] !== undefined) { 574 | response.body.trades = msg['trades'].map(x => new Trade(x)); 575 | } 576 | 577 | if (msg['lastTransactionID'] !== undefined) { 578 | response.body.lastTransactionID = msg['lastTransactionID']; 579 | } 580 | 581 | } 582 | else if (response.statusCode == 401) 583 | { 584 | } 585 | else if (response.statusCode == 404) 586 | { 587 | } 588 | else if (response.statusCode == 405) 589 | { 590 | } 591 | // 592 | // Assume standard error response with errorCode and errorMessage 593 | // 594 | else 595 | { 596 | if (msg['errorCode'] !== undefined) { 597 | response.body.errorCode = msg['errorCode']; 598 | } 599 | 600 | if (msg['errorMessage'] !== undefined) { 601 | response.body.errorMessage = msg['errorMessage']; 602 | } 603 | } 604 | } 605 | 606 | responseHandler(response); 607 | }; 608 | 609 | 610 | this.context.request( 611 | 'GET', 612 | path, 613 | body, 614 | undefined, 615 | handleResponse 616 | ); 617 | } 618 | 619 | listOpen( 620 | accountID, 621 | responseHandler 622 | ) 623 | { 624 | if (!responseHandler) 625 | { 626 | throw "No responseHandler provided for API call" 627 | } 628 | 629 | 630 | let path = '/v3/accounts/{accountID}/openTrades'; 631 | 632 | 633 | path = path.replace('{' + 'accountID' + '}', accountID); 634 | 635 | 636 | let body = {}; 637 | 638 | let handleResponse = (response) => { 639 | if (response.contentType.startsWith("application/json")) 640 | { 641 | let msg = JSON.parse(response.rawBody); 642 | 643 | response.body = {}; 644 | 645 | if (response.statusCode == 200) 646 | { 647 | if (msg['trades'] !== undefined) { 648 | response.body.trades = msg['trades'].map(x => new Trade(x)); 649 | } 650 | 651 | if (msg['lastTransactionID'] !== undefined) { 652 | response.body.lastTransactionID = msg['lastTransactionID']; 653 | } 654 | 655 | } 656 | else if (response.statusCode == 401) 657 | { 658 | } 659 | else if (response.statusCode == 404) 660 | { 661 | } 662 | else if (response.statusCode == 405) 663 | { 664 | } 665 | // 666 | // Assume standard error response with errorCode and errorMessage 667 | // 668 | else 669 | { 670 | if (msg['errorCode'] !== undefined) { 671 | response.body.errorCode = msg['errorCode']; 672 | } 673 | 674 | if (msg['errorMessage'] !== undefined) { 675 | response.body.errorMessage = msg['errorMessage']; 676 | } 677 | } 678 | } 679 | 680 | responseHandler(response); 681 | }; 682 | 683 | 684 | this.context.request( 685 | 'GET', 686 | path, 687 | body, 688 | undefined, 689 | handleResponse 690 | ); 691 | } 692 | 693 | get( 694 | accountID, 695 | tradeSpecifier, 696 | responseHandler 697 | ) 698 | { 699 | if (!responseHandler) 700 | { 701 | throw "No responseHandler provided for API call" 702 | } 703 | 704 | 705 | let path = '/v3/accounts/{accountID}/trades/{tradeSpecifier}'; 706 | 707 | 708 | path = path.replace('{' + 'accountID' + '}', accountID); 709 | path = path.replace('{' + 'tradeSpecifier' + '}', tradeSpecifier); 710 | 711 | 712 | let body = {}; 713 | 714 | let handleResponse = (response) => { 715 | if (response.contentType.startsWith("application/json")) 716 | { 717 | let msg = JSON.parse(response.rawBody); 718 | 719 | response.body = {}; 720 | 721 | if (response.statusCode == 200) 722 | { 723 | if (msg['trade'] !== undefined) { 724 | response.body.trade = new Trade(msg['trade']); 725 | } 726 | 727 | if (msg['lastTransactionID'] !== undefined) { 728 | response.body.lastTransactionID = msg['lastTransactionID']; 729 | } 730 | 731 | } 732 | else if (response.statusCode == 401) 733 | { 734 | } 735 | else if (response.statusCode == 404) 736 | { 737 | } 738 | else if (response.statusCode == 405) 739 | { 740 | } 741 | // 742 | // Assume standard error response with errorCode and errorMessage 743 | // 744 | else 745 | { 746 | if (msg['errorCode'] !== undefined) { 747 | response.body.errorCode = msg['errorCode']; 748 | } 749 | 750 | if (msg['errorMessage'] !== undefined) { 751 | response.body.errorMessage = msg['errorMessage']; 752 | } 753 | } 754 | } 755 | 756 | responseHandler(response); 757 | }; 758 | 759 | 760 | this.context.request( 761 | 'GET', 762 | path, 763 | body, 764 | undefined, 765 | handleResponse 766 | ); 767 | } 768 | 769 | close( 770 | accountID, 771 | tradeSpecifier, 772 | bodyParams, 773 | responseHandler 774 | ) 775 | { 776 | if (!responseHandler) 777 | { 778 | throw "No responseHandler provided for API call" 779 | } 780 | 781 | 782 | let path = '/v3/accounts/{accountID}/trades/{tradeSpecifier}/close'; 783 | 784 | bodyParams = bodyParams || {}; 785 | 786 | path = path.replace('{' + 'accountID' + '}', accountID); 787 | path = path.replace('{' + 'tradeSpecifier' + '}', tradeSpecifier); 788 | 789 | 790 | let body = {}; 791 | 792 | if (typeof bodyParams['units'] !== 'undefined') 793 | { 794 | body['units'] = bodyParams['units']; 795 | } 796 | 797 | let handleResponse = (response) => { 798 | if (response.contentType.startsWith("application/json")) 799 | { 800 | let msg = JSON.parse(response.rawBody); 801 | 802 | response.body = {}; 803 | 804 | if (response.statusCode == 200) 805 | { 806 | if (msg['orderCreateTransaction'] !== undefined) { 807 | response.body.orderCreateTransaction = new transaction.MarketOrderTransaction(msg['orderCreateTransaction']); 808 | } 809 | 810 | if (msg['orderFillTransaction'] !== undefined) { 811 | response.body.orderFillTransaction = new transaction.OrderFillTransaction(msg['orderFillTransaction']); 812 | } 813 | 814 | if (msg['orderCancelTransaction'] !== undefined) { 815 | response.body.orderCancelTransaction = new transaction.OrderCancelTransaction(msg['orderCancelTransaction']); 816 | } 817 | 818 | if (msg['relatedTransactionIDs'] !== undefined) { 819 | response.body.relatedTransactionIDs = msg['relatedTransactionIDs']; 820 | } 821 | 822 | if (msg['lastTransactionID'] !== undefined) { 823 | response.body.lastTransactionID = msg['lastTransactionID']; 824 | } 825 | 826 | } 827 | else if (response.statusCode == 400) 828 | { 829 | if (msg['orderRejectTransaction'] !== undefined) { 830 | response.body.orderRejectTransaction = new transaction.MarketOrderRejectTransaction(msg['orderRejectTransaction']); 831 | } 832 | 833 | if (msg['errorCode'] !== undefined) { 834 | response.body.errorCode = msg['errorCode']; 835 | } 836 | 837 | if (msg['errorMessage'] !== undefined) { 838 | response.body.errorMessage = msg['errorMessage']; 839 | } 840 | 841 | } 842 | else if (response.statusCode == 401) 843 | { 844 | } 845 | else if (response.statusCode == 404) 846 | { 847 | if (msg['orderRejectTransaction'] !== undefined) { 848 | response.body.orderRejectTransaction = new transaction.MarketOrderRejectTransaction(msg['orderRejectTransaction']); 849 | } 850 | 851 | if (msg['lastTransactionID'] !== undefined) { 852 | response.body.lastTransactionID = msg['lastTransactionID']; 853 | } 854 | 855 | if (msg['relatedTransactionIDs'] !== undefined) { 856 | response.body.relatedTransactionIDs = msg['relatedTransactionIDs']; 857 | } 858 | 859 | if (msg['errorCode'] !== undefined) { 860 | response.body.errorCode = msg['errorCode']; 861 | } 862 | 863 | if (msg['errorMessage'] !== undefined) { 864 | response.body.errorMessage = msg['errorMessage']; 865 | } 866 | 867 | } 868 | else if (response.statusCode == 405) 869 | { 870 | } 871 | // 872 | // Assume standard error response with errorCode and errorMessage 873 | // 874 | else 875 | { 876 | if (msg['errorCode'] !== undefined) { 877 | response.body.errorCode = msg['errorCode']; 878 | } 879 | 880 | if (msg['errorMessage'] !== undefined) { 881 | response.body.errorMessage = msg['errorMessage']; 882 | } 883 | } 884 | } 885 | 886 | responseHandler(response); 887 | }; 888 | 889 | 890 | this.context.request( 891 | 'PUT', 892 | path, 893 | body, 894 | undefined, 895 | handleResponse 896 | ); 897 | } 898 | 899 | setClientExtensions( 900 | accountID, 901 | tradeSpecifier, 902 | bodyParams, 903 | responseHandler 904 | ) 905 | { 906 | if (!responseHandler) 907 | { 908 | throw "No responseHandler provided for API call" 909 | } 910 | 911 | 912 | let path = '/v3/accounts/{accountID}/trades/{tradeSpecifier}/clientExtensions'; 913 | 914 | bodyParams = bodyParams || {}; 915 | 916 | path = path.replace('{' + 'accountID' + '}', accountID); 917 | path = path.replace('{' + 'tradeSpecifier' + '}', tradeSpecifier); 918 | 919 | 920 | let body = {}; 921 | 922 | if (typeof bodyParams['clientExtensions'] !== 'undefined') 923 | { 924 | body['clientExtensions'] = bodyParams['clientExtensions']; 925 | } 926 | 927 | let handleResponse = (response) => { 928 | if (response.contentType.startsWith("application/json")) 929 | { 930 | let msg = JSON.parse(response.rawBody); 931 | 932 | response.body = {}; 933 | 934 | if (response.statusCode == 200) 935 | { 936 | if (msg['tradeClientExtensionsModifyTransaction'] !== undefined) { 937 | response.body.tradeClientExtensionsModifyTransaction = new transaction.TradeClientExtensionsModifyTransaction(msg['tradeClientExtensionsModifyTransaction']); 938 | } 939 | 940 | if (msg['relatedTransactionIDs'] !== undefined) { 941 | response.body.relatedTransactionIDs = msg['relatedTransactionIDs']; 942 | } 943 | 944 | if (msg['lastTransactionID'] !== undefined) { 945 | response.body.lastTransactionID = msg['lastTransactionID']; 946 | } 947 | 948 | } 949 | else if (response.statusCode == 400) 950 | { 951 | if (msg['tradeClientExtensionsModifyRejectTransaction'] !== undefined) { 952 | response.body.tradeClientExtensionsModifyRejectTransaction = new transaction.TradeClientExtensionsModifyRejectTransaction(msg['tradeClientExtensionsModifyRejectTransaction']); 953 | } 954 | 955 | if (msg['lastTransactionID'] !== undefined) { 956 | response.body.lastTransactionID = msg['lastTransactionID']; 957 | } 958 | 959 | if (msg['relatedTransactionIDs'] !== undefined) { 960 | response.body.relatedTransactionIDs = msg['relatedTransactionIDs']; 961 | } 962 | 963 | if (msg['errorCode'] !== undefined) { 964 | response.body.errorCode = msg['errorCode']; 965 | } 966 | 967 | if (msg['errorMessage'] !== undefined) { 968 | response.body.errorMessage = msg['errorMessage']; 969 | } 970 | 971 | } 972 | else if (response.statusCode == 401) 973 | { 974 | } 975 | else if (response.statusCode == 404) 976 | { 977 | if (msg['tradeClientExtensionsModifyRejectTransaction'] !== undefined) { 978 | response.body.tradeClientExtensionsModifyRejectTransaction = new transaction.TradeClientExtensionsModifyRejectTransaction(msg['tradeClientExtensionsModifyRejectTransaction']); 979 | } 980 | 981 | if (msg['lastTransactionID'] !== undefined) { 982 | response.body.lastTransactionID = msg['lastTransactionID']; 983 | } 984 | 985 | if (msg['relatedTransactionIDs'] !== undefined) { 986 | response.body.relatedTransactionIDs = msg['relatedTransactionIDs']; 987 | } 988 | 989 | if (msg['errorCode'] !== undefined) { 990 | response.body.errorCode = msg['errorCode']; 991 | } 992 | 993 | if (msg['errorMessage'] !== undefined) { 994 | response.body.errorMessage = msg['errorMessage']; 995 | } 996 | 997 | } 998 | else if (response.statusCode == 405) 999 | { 1000 | } 1001 | // 1002 | // Assume standard error response with errorCode and errorMessage 1003 | // 1004 | else 1005 | { 1006 | if (msg['errorCode'] !== undefined) { 1007 | response.body.errorCode = msg['errorCode']; 1008 | } 1009 | 1010 | if (msg['errorMessage'] !== undefined) { 1011 | response.body.errorMessage = msg['errorMessage']; 1012 | } 1013 | } 1014 | } 1015 | 1016 | responseHandler(response); 1017 | }; 1018 | 1019 | 1020 | this.context.request( 1021 | 'PUT', 1022 | path, 1023 | body, 1024 | undefined, 1025 | handleResponse 1026 | ); 1027 | } 1028 | 1029 | setDependentOrders( 1030 | accountID, 1031 | tradeSpecifier, 1032 | bodyParams, 1033 | responseHandler 1034 | ) 1035 | { 1036 | if (!responseHandler) 1037 | { 1038 | throw "No responseHandler provided for API call" 1039 | } 1040 | 1041 | 1042 | let path = '/v3/accounts/{accountID}/trades/{tradeSpecifier}/orders'; 1043 | 1044 | bodyParams = bodyParams || {}; 1045 | 1046 | path = path.replace('{' + 'accountID' + '}', accountID); 1047 | path = path.replace('{' + 'tradeSpecifier' + '}', tradeSpecifier); 1048 | 1049 | 1050 | let body = {}; 1051 | 1052 | if (typeof bodyParams['takeProfit'] !== 'undefined') 1053 | { 1054 | body['takeProfit'] = bodyParams['takeProfit']; 1055 | } 1056 | 1057 | if (typeof bodyParams['stopLoss'] !== 'undefined') 1058 | { 1059 | body['stopLoss'] = bodyParams['stopLoss']; 1060 | } 1061 | 1062 | if (typeof bodyParams['trailingStopLoss'] !== 'undefined') 1063 | { 1064 | body['trailingStopLoss'] = bodyParams['trailingStopLoss']; 1065 | } 1066 | 1067 | let handleResponse = (response) => { 1068 | if (response.contentType.startsWith("application/json")) 1069 | { 1070 | let msg = JSON.parse(response.rawBody); 1071 | 1072 | response.body = {}; 1073 | 1074 | if (response.statusCode == 200) 1075 | { 1076 | if (msg['takeProfitOrderCancelTransaction'] !== undefined) { 1077 | response.body.takeProfitOrderCancelTransaction = new transaction.OrderCancelTransaction(msg['takeProfitOrderCancelTransaction']); 1078 | } 1079 | 1080 | if (msg['takeProfitOrderTransaction'] !== undefined) { 1081 | response.body.takeProfitOrderTransaction = new transaction.TakeProfitOrderTransaction(msg['takeProfitOrderTransaction']); 1082 | } 1083 | 1084 | if (msg['takeProfitOrderFillTransaction'] !== undefined) { 1085 | response.body.takeProfitOrderFillTransaction = new transaction.OrderFillTransaction(msg['takeProfitOrderFillTransaction']); 1086 | } 1087 | 1088 | if (msg['takeProfitOrderCreatedCancelTransaction'] !== undefined) { 1089 | response.body.takeProfitOrderCreatedCancelTransaction = new transaction.OrderCancelTransaction(msg['takeProfitOrderCreatedCancelTransaction']); 1090 | } 1091 | 1092 | if (msg['stopLossOrderCancelTransaction'] !== undefined) { 1093 | response.body.stopLossOrderCancelTransaction = new transaction.OrderCancelTransaction(msg['stopLossOrderCancelTransaction']); 1094 | } 1095 | 1096 | if (msg['stopLossOrderTransaction'] !== undefined) { 1097 | response.body.stopLossOrderTransaction = new transaction.StopLossOrderTransaction(msg['stopLossOrderTransaction']); 1098 | } 1099 | 1100 | if (msg['stopLossOrderFillTransaction'] !== undefined) { 1101 | response.body.stopLossOrderFillTransaction = new transaction.OrderFillTransaction(msg['stopLossOrderFillTransaction']); 1102 | } 1103 | 1104 | if (msg['stopLossOrderCreatedCancelTransaction'] !== undefined) { 1105 | response.body.stopLossOrderCreatedCancelTransaction = new transaction.OrderCancelTransaction(msg['stopLossOrderCreatedCancelTransaction']); 1106 | } 1107 | 1108 | if (msg['trailingStopLossOrderCancelTransaction'] !== undefined) { 1109 | response.body.trailingStopLossOrderCancelTransaction = new transaction.OrderCancelTransaction(msg['trailingStopLossOrderCancelTransaction']); 1110 | } 1111 | 1112 | if (msg['trailingStopLossOrderTransaction'] !== undefined) { 1113 | response.body.trailingStopLossOrderTransaction = new transaction.TrailingStopLossOrderTransaction(msg['trailingStopLossOrderTransaction']); 1114 | } 1115 | 1116 | if (msg['relatedTransactionIDs'] !== undefined) { 1117 | response.body.relatedTransactionIDs = msg['relatedTransactionIDs']; 1118 | } 1119 | 1120 | if (msg['lastTransactionID'] !== undefined) { 1121 | response.body.lastTransactionID = msg['lastTransactionID']; 1122 | } 1123 | 1124 | } 1125 | else if (response.statusCode == 400) 1126 | { 1127 | if (msg['takeProfitOrderCancelRejectTransaction'] !== undefined) { 1128 | response.body.takeProfitOrderCancelRejectTransaction = new transaction.OrderCancelRejectTransaction(msg['takeProfitOrderCancelRejectTransaction']); 1129 | } 1130 | 1131 | if (msg['takeProfitOrderRejectTransaction'] !== undefined) { 1132 | response.body.takeProfitOrderRejectTransaction = new transaction.TakeProfitOrderRejectTransaction(msg['takeProfitOrderRejectTransaction']); 1133 | } 1134 | 1135 | if (msg['stopLossOrderCancelRejectTransaction'] !== undefined) { 1136 | response.body.stopLossOrderCancelRejectTransaction = new transaction.OrderCancelRejectTransaction(msg['stopLossOrderCancelRejectTransaction']); 1137 | } 1138 | 1139 | if (msg['stopLossOrderRejectTransaction'] !== undefined) { 1140 | response.body.stopLossOrderRejectTransaction = new transaction.StopLossOrderRejectTransaction(msg['stopLossOrderRejectTransaction']); 1141 | } 1142 | 1143 | if (msg['trailingStopLossOrderCancelRejectTransaction'] !== undefined) { 1144 | response.body.trailingStopLossOrderCancelRejectTransaction = new transaction.OrderCancelRejectTransaction(msg['trailingStopLossOrderCancelRejectTransaction']); 1145 | } 1146 | 1147 | if (msg['trailingStopLossOrderRejectTransaction'] !== undefined) { 1148 | response.body.trailingStopLossOrderRejectTransaction = new transaction.TrailingStopLossOrderRejectTransaction(msg['trailingStopLossOrderRejectTransaction']); 1149 | } 1150 | 1151 | if (msg['lastTransactionID'] !== undefined) { 1152 | response.body.lastTransactionID = msg['lastTransactionID']; 1153 | } 1154 | 1155 | if (msg['relatedTransactionIDs'] !== undefined) { 1156 | response.body.relatedTransactionIDs = msg['relatedTransactionIDs']; 1157 | } 1158 | 1159 | if (msg['errorCode'] !== undefined) { 1160 | response.body.errorCode = msg['errorCode']; 1161 | } 1162 | 1163 | if (msg['errorMessage'] !== undefined) { 1164 | response.body.errorMessage = msg['errorMessage']; 1165 | } 1166 | 1167 | } 1168 | else if (response.statusCode == 401) 1169 | { 1170 | } 1171 | else if (response.statusCode == 404) 1172 | { 1173 | } 1174 | else if (response.statusCode == 405) 1175 | { 1176 | } 1177 | // 1178 | // Assume standard error response with errorCode and errorMessage 1179 | // 1180 | else 1181 | { 1182 | if (msg['errorCode'] !== undefined) { 1183 | response.body.errorCode = msg['errorCode']; 1184 | } 1185 | 1186 | if (msg['errorMessage'] !== undefined) { 1187 | response.body.errorMessage = msg['errorMessage']; 1188 | } 1189 | } 1190 | } 1191 | 1192 | responseHandler(response); 1193 | }; 1194 | 1195 | 1196 | this.context.request( 1197 | 'PUT', 1198 | path, 1199 | body, 1200 | undefined, 1201 | handleResponse 1202 | ); 1203 | } 1204 | 1205 | 1206 | 1207 | } 1208 | 1209 | exports.Trade = Trade; 1210 | exports.TradeSummary = TradeSummary; 1211 | exports.CalculatedTradeState = CalculatedTradeState; 1212 | 1213 | exports.EntitySpec = EntitySpec; 1214 | -------------------------------------------------------------------------------- /src/user.js: -------------------------------------------------------------------------------- 1 | /* jshint esversion: 6 */ 2 | 3 | "use strict"; 4 | 5 | var Definition = require('./base').Definition; 6 | var Property = require('./base').Property; 7 | var Field = require('./base').Field; 8 | 9 | 10 | 11 | 12 | const UserInfo_Properties = [ 13 | new Property( 14 | 'username', 15 | 'username', 16 | "The user-provided username.", 17 | 'primitive', 18 | 'string' 19 | ), 20 | new Property( 21 | 'userID', 22 | 'userID', 23 | "The user's OANDA-assigned user ID.", 24 | 'primitive', 25 | 'integer' 26 | ), 27 | new Property( 28 | 'country', 29 | 'country', 30 | "The country that the user is based in.", 31 | 'primitive', 32 | 'string' 33 | ), 34 | new Property( 35 | 'emailAddress', 36 | 'emailAddress', 37 | "The user's email address.", 38 | 'primitive', 39 | 'string' 40 | ), 41 | ]; 42 | 43 | class UserInfo extends Definition { 44 | constructor(data) { 45 | super(); 46 | 47 | this._summaryFormat = ""; 48 | 49 | this._nameFormat = ""; 50 | 51 | this._properties = UserInfo_Properties; 52 | 53 | data = data || {}; 54 | 55 | if (data['username'] !== undefined) { 56 | this.username = data['username']; 57 | } 58 | 59 | if (data['userID'] !== undefined) { 60 | this.userID = data['userID']; 61 | } 62 | 63 | if (data['country'] !== undefined) { 64 | this.country = data['country']; 65 | } 66 | 67 | if (data['emailAddress'] !== undefined) { 68 | this.emailAddress = data['emailAddress']; 69 | } 70 | 71 | } 72 | } 73 | 74 | const UserInfoExternal_Properties = [ 75 | new Property( 76 | 'userID', 77 | 'userID', 78 | "The user's OANDA-assigned user ID.", 79 | 'primitive', 80 | 'integer' 81 | ), 82 | new Property( 83 | 'country', 84 | 'country', 85 | "The country that the user is based in.", 86 | 'primitive', 87 | 'string' 88 | ), 89 | new Property( 90 | 'FIFO', 91 | 'FIFO', 92 | "Flag indicating if the the user's Accounts adhere to FIFO execution rules.", 93 | 'primitive', 94 | 'boolean' 95 | ), 96 | ]; 97 | 98 | class UserInfoExternal extends Definition { 99 | constructor(data) { 100 | super(); 101 | 102 | this._summaryFormat = ""; 103 | 104 | this._nameFormat = ""; 105 | 106 | this._properties = UserInfoExternal_Properties; 107 | 108 | data = data || {}; 109 | 110 | if (data['userID'] !== undefined) { 111 | this.userID = data['userID']; 112 | } 113 | 114 | if (data['country'] !== undefined) { 115 | this.country = data['country']; 116 | } 117 | 118 | if (data['FIFO'] !== undefined) { 119 | this.FIFO = data['FIFO']; 120 | } 121 | 122 | } 123 | } 124 | 125 | class EntitySpec { 126 | constructor(context) { 127 | this.context = context; 128 | this.UserInfo = UserInfo; 129 | this.UserInfoExternal = UserInfoExternal; 130 | } 131 | 132 | getInfo( 133 | userSpecifier, 134 | responseHandler 135 | ) 136 | { 137 | if (!responseHandler) 138 | { 139 | throw "No responseHandler provided for API call" 140 | } 141 | 142 | 143 | let path = '/v3/users/{userSpecifier}'; 144 | 145 | 146 | path = path.replace('{' + 'userSpecifier' + '}', userSpecifier); 147 | 148 | 149 | let body = {}; 150 | 151 | let handleResponse = (response) => { 152 | if (response.contentType.startsWith("application/json")) 153 | { 154 | let msg = JSON.parse(response.rawBody); 155 | 156 | response.body = {}; 157 | 158 | if (response.statusCode == 200) 159 | { 160 | if (msg['userInfo'] !== undefined) { 161 | response.body.userInfo = new UserInfo(msg['userInfo']); 162 | } 163 | 164 | } 165 | else if (response.statusCode == 401) 166 | { 167 | } 168 | else if (response.statusCode == 403) 169 | { 170 | } 171 | else if (response.statusCode == 405) 172 | { 173 | } 174 | // 175 | // Assume standard error response with errorCode and errorMessage 176 | // 177 | else 178 | { 179 | if (msg['errorCode'] !== undefined) { 180 | response.body.errorCode = msg['errorCode']; 181 | } 182 | 183 | if (msg['errorMessage'] !== undefined) { 184 | response.body.errorMessage = msg['errorMessage']; 185 | } 186 | } 187 | } 188 | 189 | responseHandler(response); 190 | }; 191 | 192 | 193 | this.context.request( 194 | 'GET', 195 | path, 196 | body, 197 | undefined, 198 | handleResponse 199 | ); 200 | } 201 | 202 | getExternalInfo( 203 | userSpecifier, 204 | responseHandler 205 | ) 206 | { 207 | if (!responseHandler) 208 | { 209 | throw "No responseHandler provided for API call" 210 | } 211 | 212 | 213 | let path = '/v3/users/{userSpecifier}/externalInfo'; 214 | 215 | 216 | path = path.replace('{' + 'userSpecifier' + '}', userSpecifier); 217 | 218 | 219 | let body = {}; 220 | 221 | let handleResponse = (response) => { 222 | if (response.contentType.startsWith("application/json")) 223 | { 224 | let msg = JSON.parse(response.rawBody); 225 | 226 | response.body = {}; 227 | 228 | if (response.statusCode == 200) 229 | { 230 | if (msg['userInfo'] !== undefined) { 231 | response.body.userInfo = new UserInfoExternal(msg['userInfo']); 232 | } 233 | 234 | } 235 | else if (response.statusCode == 401) 236 | { 237 | } 238 | else if (response.statusCode == 403) 239 | { 240 | } 241 | else if (response.statusCode == 405) 242 | { 243 | } 244 | // 245 | // Assume standard error response with errorCode and errorMessage 246 | // 247 | else 248 | { 249 | if (msg['errorCode'] !== undefined) { 250 | response.body.errorCode = msg['errorCode']; 251 | } 252 | 253 | if (msg['errorMessage'] !== undefined) { 254 | response.body.errorMessage = msg['errorMessage']; 255 | } 256 | } 257 | } 258 | 259 | responseHandler(response); 260 | }; 261 | 262 | 263 | this.context.request( 264 | 'GET', 265 | path, 266 | body, 267 | undefined, 268 | handleResponse 269 | ); 270 | } 271 | 272 | 273 | 274 | } 275 | 276 | exports.UserInfo = UserInfo; 277 | exports.UserInfoExternal = UserInfoExternal; 278 | 279 | exports.EntitySpec = EntitySpec; 280 | -------------------------------------------------------------------------------- /v20-3.0.1.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oanda/v20-javascript/b5fc9c37e365483eb0367022d9c0e8514df47e07/v20-3.0.1.tar.gz -------------------------------------------------------------------------------- /v20-3.0.10.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oanda/v20-javascript/b5fc9c37e365483eb0367022d9c0e8514df47e07/v20-3.0.10.tar.gz -------------------------------------------------------------------------------- /v20-3.0.11.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oanda/v20-javascript/b5fc9c37e365483eb0367022d9c0e8514df47e07/v20-3.0.11.tar.gz -------------------------------------------------------------------------------- /v20-3.0.13.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oanda/v20-javascript/b5fc9c37e365483eb0367022d9c0e8514df47e07/v20-3.0.13.tar.gz -------------------------------------------------------------------------------- /v20-3.0.14.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oanda/v20-javascript/b5fc9c37e365483eb0367022d9c0e8514df47e07/v20-3.0.14.tar.gz -------------------------------------------------------------------------------- /v20-3.0.15.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oanda/v20-javascript/b5fc9c37e365483eb0367022d9c0e8514df47e07/v20-3.0.15.tar.gz -------------------------------------------------------------------------------- /v20-3.0.16.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oanda/v20-javascript/b5fc9c37e365483eb0367022d9c0e8514df47e07/v20-3.0.16.tar.gz -------------------------------------------------------------------------------- /v20-3.0.18.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oanda/v20-javascript/b5fc9c37e365483eb0367022d9c0e8514df47e07/v20-3.0.18.tar.gz -------------------------------------------------------------------------------- /v20-3.0.2.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oanda/v20-javascript/b5fc9c37e365483eb0367022d9c0e8514df47e07/v20-3.0.2.tar.gz -------------------------------------------------------------------------------- /v20-3.0.22.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oanda/v20-javascript/b5fc9c37e365483eb0367022d9c0e8514df47e07/v20-3.0.22.tar.gz -------------------------------------------------------------------------------- /v20-3.0.25.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oanda/v20-javascript/b5fc9c37e365483eb0367022d9c0e8514df47e07/v20-3.0.25.tar.gz -------------------------------------------------------------------------------- /v20-3.0.3.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oanda/v20-javascript/b5fc9c37e365483eb0367022d9c0e8514df47e07/v20-3.0.3.tar.gz -------------------------------------------------------------------------------- /v20-3.0.4.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oanda/v20-javascript/b5fc9c37e365483eb0367022d9c0e8514df47e07/v20-3.0.4.tar.gz -------------------------------------------------------------------------------- /v20-3.0.5.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oanda/v20-javascript/b5fc9c37e365483eb0367022d9c0e8514df47e07/v20-3.0.5.tar.gz -------------------------------------------------------------------------------- /v20-3.0.6.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oanda/v20-javascript/b5fc9c37e365483eb0367022d9c0e8514df47e07/v20-3.0.6.tar.gz -------------------------------------------------------------------------------- /v20-3.0.7.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oanda/v20-javascript/b5fc9c37e365483eb0367022d9c0e8514df47e07/v20-3.0.7.tar.gz -------------------------------------------------------------------------------- /v20-3.0.8.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oanda/v20-javascript/b5fc9c37e365483eb0367022d9c0e8514df47e07/v20-3.0.8.tar.gz -------------------------------------------------------------------------------- /v20-3.0.9.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oanda/v20-javascript/b5fc9c37e365483eb0367022d9c0e8514df47e07/v20-3.0.9.tar.gz --------------------------------------------------------------------------------