From f25314c7af06e247ceae7d073d6ceff58dba91a3 Mon Sep 17 00:00:00 2001 From: Peter Oliha Date: Mon, 18 Dec 2017 13:46:36 +0100 Subject: [PATCH 1/2] trade aggregation --- src/orderbook_call_builder.js | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/orderbook_call_builder.js b/src/orderbook_call_builder.js index adcc38e2e..9ca9ea310 100644 --- a/src/orderbook_call_builder.js +++ b/src/orderbook_call_builder.js @@ -38,5 +38,20 @@ export class OrderbookCallBuilder extends CallBuilder { this.filter.push(['order_book', 'trades']); return this; } + + /** + * Trade Aggregations facilitate efficient gathering of historical trade data + * @param {long} start_time lower time boundary represented as millis since epoch + * @param {long} end_time upper time boundary represented as millis since epoch + * @returns {OrderbookCallBuilder} + */ + tradeAggregation(start_time, end_time){ + if ((typeof start_time === 'undefined') || (typeof end_time === 'undefined')) { + throw new BadRequestError("Invalid time bounds", [start_time, end_time]); + } + this.url.addQuery("start_time", start_time); + this.url.addQuery("end_time", end_time); + return this; + } } From d363f8870f36af4dac932b2497b82211d396306b Mon Sep 17 00:00:00 2001 From: Peter Oliha Date: Tue, 19 Dec 2017 19:59:49 +0100 Subject: [PATCH 2/2] tradeaggregation call builder --- src/orderbook_call_builder.js | 14 ----- src/server.js | 15 +++++ src/trade_aggregation_call_builder.js | 58 +++++++++++++++++++ test/unit/server_test.js | 83 +++++++++++++++++++++------ 4 files changed, 140 insertions(+), 30 deletions(-) create mode 100644 src/trade_aggregation_call_builder.js diff --git a/src/orderbook_call_builder.js b/src/orderbook_call_builder.js index 9ca9ea310..ca6ab579b 100644 --- a/src/orderbook_call_builder.js +++ b/src/orderbook_call_builder.js @@ -39,19 +39,5 @@ export class OrderbookCallBuilder extends CallBuilder { return this; } - /** - * Trade Aggregations facilitate efficient gathering of historical trade data - * @param {long} start_time lower time boundary represented as millis since epoch - * @param {long} end_time upper time boundary represented as millis since epoch - * @returns {OrderbookCallBuilder} - */ - tradeAggregation(start_time, end_time){ - if ((typeof start_time === 'undefined') || (typeof end_time === 'undefined')) { - throw new BadRequestError("Invalid time bounds", [start_time, end_time]); - } - this.url.addQuery("start_time", start_time); - this.url.addQuery("end_time", end_time); - return this; - } } diff --git a/src/server.js b/src/server.js index ee49ef68c..213418bf1 100644 --- a/src/server.js +++ b/src/server.js @@ -12,6 +12,7 @@ import {PathCallBuilder} from "./path_call_builder"; import {PaymentCallBuilder} from "./payment_call_builder"; import {EffectCallBuilder} from "./effect_call_builder"; import {FriendbotBuilder} from "./friendbot_builder"; +import { TradeAggregationCallBuilder } from "./trade_aggregation_call_builder"; import {xdr} from "stellar-base"; import isString from "lodash/isString"; @@ -194,4 +195,18 @@ export class Server { return new AccountResponse(res); }); } + + /** + * + * @param {Asset} base base aseet + * @param {Asset} counter counter asset + * @param {long} start_time lower time boundary represented as millis since epoch + * @param {long} end_time upper time boundary represented as millis since epoch + * @param {long} resolution segment duration as millis since epoch. *Supported values are 5 minutes (300000), 15 minutes (900000), 1 hour (3600000), 1 day (86400000) and 1 week (604800000). + * Returns new {@link TradeAggregationCallBuilder} object configured with the current Horizon server configuration. + * @returns {TradeAggregationCallBuilder} + */ + tradeAggregation(base, counter, start_time, end_time, resolution){ + return new TradeAggregationCallBuilder(URI(this.serverURL), base, counter, start_time, end_time, resolution); + } } diff --git a/src/trade_aggregation_call_builder.js b/src/trade_aggregation_call_builder.js new file mode 100644 index 000000000..35fbb5f6c --- /dev/null +++ b/src/trade_aggregation_call_builder.js @@ -0,0 +1,58 @@ +import { CallBuilder } from "./call_builder"; +import { NotFoundError, NetworkError, BadRequestError } from "./errors"; + +/** + * Trade Aggregations facilitate efficient gathering of historical trade data + * Do not create this object directly, use {@link Server#tradeAggregation}. + * @param {string} serverUrl serverUrl Horizon server URL. + * @param {Asset} base base asset + * @param {Asset} counter counter asset + * @param {long} start_time lower time boundary represented as millis since epoch + * @param {long} end_time upper time boundary represented as millis since epoch + * @param {long} resolution segment duration as millis since epoch. *Supported values are 5 minutes (300000), 15 minutes (900000), 1 hour (3600000), 1 day (86400000) and 1 week (604800000). + * @returns {OrderbookCallBuilder} + */ +export class TradeAggregationCallBuilder extends CallBuilder { + constructor (serverUrl, base, counter, start_time, end_time, resolution){ + super(serverUrl); + this.allowedResolutions = [300000, 900000, 3600000, 86400000, 604800000]; + this.url.segment('trade_aggregations'); + if (!base.isNative()) { + this.url.addQuery("base_asset_type", base.getAssetType()); + this.url.addQuery("base_asset_code", base.getCode()); + this.url.addQuery("base_asset_issuer", base.getIssuer()); + } else { + this.url.addQuery("base_asset_type", 'native'); + } + if (!counter.isNative()) { + this.url.addQuery("counter_asset_type", counter.getAssetType()); + this.url.addQuery("counter_asset_code", counter.getCode()); + this.url.addQuery("counter_asset_issuer", counter.getIssuer()); + } else { + this.url.addQuery("counter_asset_type", 'native'); + } + if ((typeof start_time === 'undefined') || (typeof end_time === 'undefined')) { + throw new BadRequestError("Invalid time bounds", [start_time, end_time]); + }else{ + this.url.addQuery("start_time", start_time); + this.url.addQuery("end_time", end_time); + } + if (!this.isValidResolution(resolution)) { + throw new BadRequestError("Invalid resolution", resolution); + }else{ + this.url.addQuery("resolution", resolution); + } + + + } + + /** + * @private + * @param {long} resolution + */ + isValidResolution(resolution){ + return this.allowedResolutions.includes(resolution); + } + + +} \ No newline at end of file diff --git a/test/unit/server_test.js b/test/unit/server_test.js index 8cd6e71cc..4f31915e3 100644 --- a/test/unit/server_test.js +++ b/test/unit/server_test.js @@ -750,24 +750,24 @@ describe("server.js tests", function () { } }; - it("requests the correct endpoint", function (done) { - this.axiosMock.expects('get') - .withArgs(sinon.match('https://horizon-live.stellar.org:1337/paths?destination_account=GAEDTJ4PPEFVW5XV2S7LUXBEHNQMX5Q2GM562RJGOQG7GVCE5H3HIB4V&source_account=GARSFJNXJIHO6ULUBK3DBYKVSIZE7SC72S5DYBCHU7DKL22UXKVD7MXP&destination_amount=20.0&destination_asset_type=credit_alphanum4&destination_asset_code=EUR&destination_asset_issuer=GDSBCQO34HWPGUGQSP3QBFEXVTSR2PW46UIGTHVWGWJGQKH3AFNHXHXN')) - .returns(Promise.resolve({data: pathsResponse})); - - this.server.paths("GARSFJNXJIHO6ULUBK3DBYKVSIZE7SC72S5DYBCHU7DKL22UXKVD7MXP","GAEDTJ4PPEFVW5XV2S7LUXBEHNQMX5Q2GM562RJGOQG7GVCE5H3HIB4V", new StellarSdk.Asset('EUR', 'GDSBCQO34HWPGUGQSP3QBFEXVTSR2PW46UIGTHVWGWJGQKH3AFNHXHXN'), '20.0') - .call() - .then(function (response) { - expect(response.records).to.be.deep.equal(pathsResponse._embedded.records); - expect(response.next).to.be.function; - expect(response.prev).to.be.function; - done(); + it("requests the correct endpoint", function (done) { + this.axiosMock.expects('get') + .withArgs(sinon.match('https://horizon-live.stellar.org:1337/paths?destination_account=GAEDTJ4PPEFVW5XV2S7LUXBEHNQMX5Q2GM562RJGOQG7GVCE5H3HIB4V&source_account=GARSFJNXJIHO6ULUBK3DBYKVSIZE7SC72S5DYBCHU7DKL22UXKVD7MXP&destination_amount=20.0&destination_asset_type=credit_alphanum4&destination_asset_code=EUR&destination_asset_issuer=GDSBCQO34HWPGUGQSP3QBFEXVTSR2PW46UIGTHVWGWJGQKH3AFNHXHXN')) + .returns(Promise.resolve({data: pathsResponse})); + + this.server.paths("GARSFJNXJIHO6ULUBK3DBYKVSIZE7SC72S5DYBCHU7DKL22UXKVD7MXP","GAEDTJ4PPEFVW5XV2S7LUXBEHNQMX5Q2GM562RJGOQG7GVCE5H3HIB4V", new StellarSdk.Asset('EUR', 'GDSBCQO34HWPGUGQSP3QBFEXVTSR2PW46UIGTHVWGWJGQKH3AFNHXHXN'), '20.0') + .call() + .then(function (response) { + expect(response.records).to.be.deep.equal(pathsResponse._embedded.records); + expect(response.next).to.be.function; + expect(response.prev).to.be.function; + done(); + }) + .catch(function (err) { + done(err); }) - .catch(function (err) { - done(err); - }) + }); }); - }); describe("EffectCallBuilder", function() { let effectsResponse = { @@ -1117,5 +1117,56 @@ describe("server.js tests", function () { }) }); }); + + describe("TradeAggregationCallBuilder", function () { + let tradeAggregationResponse = +{ + "_links": { + "self": { + "href": "https://horizon.stellar.org/trade_aggregations?base_asset_type=native\u0026start_time=1512689100000\u0026counter_asset_issuer=GATEMHCCKCY67ZUCKTROYN24ZYT5GK4EQZ65JJLDHKHRUZI3EUEKMTCH\u0026limit=200\u0026end_time=1512775500000\u0026counter_asset_type=credit_alphanum4\u0026resolution=300000\u0026order=asc\u0026counter_asset_code=BTC" + }, + "next": { + "href": "https://horizon.stellar.org/trade_aggregations?base_asset_type=native\u0026counter_asset_code=BTC\u0026counter_asset_issuer=GATEMHCCKCY67ZUCKTROYN24ZYT5GK4EQZ65JJLDHKHRUZI3EUEKMTCH\u0026counter_asset_type=credit_alphanum4\u0026end_time=1512775500000\u0026limit=200\u0026order=asc\u0026resolution=300000\u0026start_time=1512765000000" + } + }, + "_embedded": { + "records": [] + } + } + + it("requests the correct endpoint native/credit", function (done) { + this.axiosMock.expects('get') + .withArgs(sinon.match('https://horizon-live.stellar.org:1337/trade_aggregations?base_asset_type=native&counter_asset_type=credit_alphanum4&counter_asset_code=USD&counter_asset_issuer=GDVDKQFP665JAO7A2LSHNLQIUNYNAAIGJ6FYJVMG4DT3YJQQJSRBLQDG&start_time=1512689100000&end_time=1512775500000&resolution=300000')) + .returns(Promise.resolve({ data: tradeAggregationResponse })); + + this.server.tradeAggregation(StellarSdk.Asset.native(), new StellarSdk.Asset('USD', "GDVDKQFP665JAO7A2LSHNLQIUNYNAAIGJ6FYJVMG4DT3YJQQJSRBLQDG"), 1512689100000, 1512775500000, 300000) + .call() + .then(function (response) { + expect(response).to.be.deep.equal(tradeAggregationResponse); + done(); + }) + .catch(function (err) { + done(err); + }) + }); + + it("requests the correct endpoint credit/native", function (done) { + this.axiosMock.expects('get') + .withArgs(sinon.match('https://horizon-live.stellar.org:1337/trade_aggregations?base_asset_type=credit_alphanum4&base_asset_code=USD&base_asset_issuer=GDVDKQFP665JAO7A2LSHNLQIUNYNAAIGJ6FYJVMG4DT3YJQQJSRBLQDG&counter_asset_type=native&start_time=1512689100000&end_time=1512775500000&resolution=300000')) + .returns(Promise.resolve({ data: tradeAggregationResponse })); + + this.server.tradeAggregation(new StellarSdk.Asset('USD', "GDVDKQFP665JAO7A2LSHNLQIUNYNAAIGJ6FYJVMG4DT3YJQQJSRBLQDG"), StellarSdk.Asset.native(), 1512689100000, 1512775500000, 300000) + .call() + .then(function (response) { + expect(response).to.be.deep.equal(tradeAggregationResponse); + done(); + }) + .catch(function (err) { + done(err); + }) + }); + + }); + + }) });