From 65bbc248d942b9e6aa2bf25105515f202cecc4fb Mon Sep 17 00:00:00 2001 From: Vladimir Voronkov Date: Tue, 3 Jan 2023 11:48:54 +0200 Subject: [PATCH 01/18] Add WeightedAveragesReport service type --- workers/loc.api/di/types.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/workers/loc.api/di/types.js b/workers/loc.api/di/types.js index 06eefc171..e0c5746e1 100644 --- a/workers/loc.api/di/types.js +++ b/workers/loc.api/di/types.js @@ -66,5 +66,6 @@ module.exports = { SyncTempTablesManager: Symbol.for('SyncTempTablesManager'), SyncUserStepManager: Symbol.for('SyncUserStepManager'), SyncUserStepData: Symbol.for('SyncUserStepData'), - SyncUserStepDataFactory: Symbol.for('SyncUserStepDataFactory') + SyncUserStepDataFactory: Symbol.for('SyncUserStepDataFactory'), + WeightedAveragesReport: Symbol.for('WeightedAveragesReport') } From ea272eaea166cc46c0e077ceeed31527c4881119 Mon Sep 17 00:00:00 2001 From: Vladimir Voronkov Date: Tue, 3 Jan 2023 11:50:03 +0200 Subject: [PATCH 02/18] Make WeightedAveragesReport service --- .../sync/weighted.averages.report/index.js | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 workers/loc.api/sync/weighted.averages.report/index.js diff --git a/workers/loc.api/sync/weighted.averages.report/index.js b/workers/loc.api/sync/weighted.averages.report/index.js new file mode 100644 index 000000000..776039fbd --- /dev/null +++ b/workers/loc.api/sync/weighted.averages.report/index.js @@ -0,0 +1,41 @@ +'use strict' + +const { decorateInjectable } = require('../../di/utils') + +const depsTypes = (TYPES) => [ + TYPES.DAO, + TYPES.Authenticator, + TYPES.Trades +] +class WeightedAveragesReport { + constructor ( + dao, + authenticator, + trades + ) { + this.dao = dao + this.authenticator = authenticator + this.trades = trades + } + + async getWeightedAveragesReport (args = {}) { + const { + auth = {}, + params = {} + } = args ?? {} + const { + start = 0, + end = Date.now(), + symbol = [] + } = params ?? {} + const user = await this.authenticator + .verifyRequestUser({ auth }) + const symbolArr = Array.isArray(symbol) + ? symbol + : [symbol] + } +} + +decorateInjectable(WeightedAveragesReport, depsTypes) + +module.exports = WeightedAveragesReport From 4e9d784f28f9d25a9fe99688bfbfd79a60169e21 Mon Sep 17 00:00:00 2001 From: Vladimir Voronkov Date: Tue, 3 Jan 2023 11:50:46 +0200 Subject: [PATCH 03/18] Add WeightedAveragesReport service to di --- workers/loc.api/di/app.deps.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/workers/loc.api/di/app.deps.js b/workers/loc.api/di/app.deps.js index 0517e2d87..119802ead 100644 --- a/workers/loc.api/di/app.deps.js +++ b/workers/loc.api/di/app.deps.js @@ -93,6 +93,7 @@ const { fullTaxReportCsvWriter } = require('../generate-csv/csv-writer') const FullTaxReport = require('../sync/full.tax.report') +const WeightedAveragesReport = require('../sync/weighted.averages.report') const SqliteDbMigrator = require( '../sync/dao/db-migrations/sqlite.db.migrator' ) @@ -152,6 +153,7 @@ module.exports = ({ ['_syncCollsManager', TYPES.SyncCollsManager], ['_dataConsistencyChecker', TYPES.DataConsistencyChecker], ['_winLossVSAccountBalance', TYPES.WinLossVSAccountBalance], + ['_weightedAveragesReport', TYPES.WeightedAveragesReport], ['_getDataFromApi', TYPES.GetDataFromApi] ] }) @@ -360,6 +362,8 @@ module.exports = ({ ) bind(TYPES.FullTaxReport) .to(FullTaxReport) + bind(TYPES.WeightedAveragesReport) + .to(WeightedAveragesReport) rebind(TYPES.CsvJobData) .to(CsvJobData) .inSingletonScope() From eec5820a2cf29a2a04eaebaa52693a84c45cab29 Mon Sep 17 00:00:00 2001 From: Vladimir Voronkov Date: Tue, 3 Jan 2023 11:51:51 +0200 Subject: [PATCH 04/18] Add getWeightedAveragesReport endpoint to main service --- workers/loc.api/service.report.framework.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/workers/loc.api/service.report.framework.js b/workers/loc.api/service.report.framework.js index b8900f965..3fd22633a 100644 --- a/workers/loc.api/service.report.framework.js +++ b/workers/loc.api/service.report.framework.js @@ -1322,6 +1322,15 @@ class FrameworkReportService extends ReportService { }, 'getWinLossVSAccountBalance', args, cb) } + getWeightedAveragesReport (space, args, cb) { + return this._privResponder(async () => { + checkParams(args, 'paramsSchemaForWeightedAveragesReportApi') + + return this._weightedAveragesReport + .getWeightedAveragesReport(args) + }, 'getWeightedAveragesReport', args, cb) + } + /** * @override */ From 72846a85d5a7317e007600d3bd1b295b53fae10d Mon Sep 17 00:00:00 2001 From: Vladimir Voronkov Date: Tue, 3 Jan 2023 11:52:54 +0200 Subject: [PATCH 05/18] Add params schema for getWeightedAveragesReport endpoint --- workers/loc.api/helpers/schema.js | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/workers/loc.api/helpers/schema.js b/workers/loc.api/helpers/schema.js index 6fbb2d89e..69af3383d 100644 --- a/workers/loc.api/helpers/schema.js +++ b/workers/loc.api/helpers/schema.js @@ -259,6 +259,21 @@ const paramsSchemaForWinLossVSAccountBalanceApi = { } } +const paramsSchemaForWeightedAveragesReportApi = { + type: 'object', + properties: { + start: { + type: 'integer' + }, + end: { + type: 'integer' + }, + symbol: { + type: ['string', 'array'] + } + } +} + const paramsSchemaForTradedVolumeApi = { type: 'object', properties: { @@ -445,6 +460,7 @@ module.exports = { paramsSchemaForBalanceHistoryApi, paramsSchemaForWinLossApi, paramsSchemaForWinLossVSAccountBalanceApi, + paramsSchemaForWeightedAveragesReportApi, paramsSchemaForPositionsSnapshotApi, paramsSchemaForFullSnapshotReportApi, paramsSchemaForFullTaxReportApi, From 236e603cd01c9b4d1105f3083796305c0cba0f2a Mon Sep 17 00:00:00 2001 From: Vladimir Voronkov Date: Tue, 3 Jan 2023 12:51:53 +0200 Subject: [PATCH 06/18] Add getWeightedAveragesReportCsv endpoint to main service --- workers/loc.api/service.report.framework.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/workers/loc.api/service.report.framework.js b/workers/loc.api/service.report.framework.js index 3fd22633a..fa863ee28 100644 --- a/workers/loc.api/service.report.framework.js +++ b/workers/loc.api/service.report.framework.js @@ -1435,6 +1435,15 @@ class FrameworkReportService extends ReportService { ) }, 'getWinLossVSAccountBalanceCsv', args, cb) } + + getWeightedAveragesReportCsv (space, args, cb) { + return this._responder(() => { + return this._generateCsv( + 'getWeightedAveragesReportCsvJobData', + args + ) + }, 'getWeightedAveragesReportCsv', args, cb) + } } module.exports = FrameworkReportService From ad552f0df4ec2fe03c82eda9b7284a59b602933e Mon Sep 17 00:00:00 2001 From: Vladimir Voronkov Date: Tue, 3 Jan 2023 12:52:22 +0200 Subject: [PATCH 07/18] Add params schema for getWeightedAveragesReportCsv endpoint --- workers/loc.api/helpers/schema.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/workers/loc.api/helpers/schema.js b/workers/loc.api/helpers/schema.js index 69af3383d..03142f22e 100644 --- a/workers/loc.api/helpers/schema.js +++ b/workers/loc.api/helpers/schema.js @@ -384,6 +384,15 @@ const paramsSchemaForWinLossVSAccountBalanceCsv = { } } +const paramsSchemaForWeightedAveragesReportApiCsv = { + type: 'object', + properties: { + ...cloneDeep(paramsSchemaForWeightedAveragesReportApi.properties), + timezone, + dateFormat + } +} + const paramsSchemaForPositionsSnapshotCsv = { type: 'object', properties: { @@ -471,6 +480,7 @@ module.exports = { paramsSchemaForBalanceHistoryCsv, paramsSchemaForWinLossCsv, paramsSchemaForWinLossVSAccountBalanceCsv, + paramsSchemaForWeightedAveragesReportApiCsv, paramsSchemaForPositionsSnapshotCsv, paramsSchemaForFullSnapshotReportCsv, paramsSchemaForFullTaxReportCsv, From 6cf50ea415ab7e546b49a1422e5bc356c410c086 Mon Sep 17 00:00:00 2001 From: Vladimir Voronkov Date: Tue, 3 Jan 2023 12:54:14 +0200 Subject: [PATCH 08/18] Add csv job data for weighted averages report --- workers/loc.api/generate-csv/csv.job.data.js | 55 +++++++++++++++++++- 1 file changed, 53 insertions(+), 2 deletions(-) diff --git a/workers/loc.api/generate-csv/csv.job.data.js b/workers/loc.api/generate-csv/csv.job.data.js index c769bb234..ac34621a1 100644 --- a/workers/loc.api/generate-csv/csv.job.data.js +++ b/workers/loc.api/generate-csv/csv.job.data.js @@ -20,18 +20,21 @@ const { decorateInjectable } = require('../di/utils') const depsTypes = (TYPES) => [ TYPES.RService, TYPES.FullSnapshotReportCsvWriter, - TYPES.FullTaxReportCsvWriter + TYPES.FullTaxReportCsvWriter, + TYPES.WeightedAveragesReportCsv ] class CsvJobData extends BaseCsvJobData { constructor ( rService, fullSnapshotReportCsvWriter, - fullTaxReportCsvWriter + fullTaxReportCsvWriter, + weightedAveragesReportCsv ) { super(rService) this.fullSnapshotReportCsvWriter = fullSnapshotReportCsvWriter this.fullTaxReportCsvWriter = fullTaxReportCsvWriter + this.weightedAveragesReportCsv = weightedAveragesReportCsv } _addColumnsBySchema (columnsCsv = {}, schema = {}) { @@ -667,6 +670,54 @@ class CsvJobData extends BaseCsvJobData { return jobData } + + async getWeightedAveragesReportCsvJobData ( + args, + uId, + uInfo + ) { + checkParams(args, 'paramsSchemaForWeightedAveragesReportApiCsv') + + const { + userId, + userInfo + } = await checkJobAndGetUserData( + this.rService, + uId, + uInfo + ) + + const csvArgs = getCsvArgs(args) + + const jobData = { + userInfo, + userId, + name: 'getWeightedAveragesReport', + fileNamesMap: [['getWeightedAveragesReport', 'weighted-averages-report']], + args: csvArgs, + columnsCsv: { + symbol: 'PAIR', + final: { + weightedPrice: 'WEIGHTED PRICE', + amount: 'AMOUNT' + }, + buying: { + weightedPrice: 'WEIGHTED PRICE', + amount: 'AMOUNT' + }, + selling: { + weightedPrice: 'WEIGHTED PRICE', + amount: 'AMOUNT' + } + }, + formatSettings: { + symbol: 'symbol' + }, + csvCustomWriter: this.weightedAveragesReportCsvWriter + } + + return jobData + } } decorateInjectable(CsvJobData, depsTypes) From b355dc1bc9571895fa89590b80310fa9f73e39a4 Mon Sep 17 00:00:00 2001 From: Vladimir Voronkov Date: Wed, 4 Jan 2023 12:50:29 +0200 Subject: [PATCH 09/18] Add WeightedAveragesReportCsvWriter service type --- workers/loc.api/di/types.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/workers/loc.api/di/types.js b/workers/loc.api/di/types.js index e0c5746e1..b970ec5ba 100644 --- a/workers/loc.api/di/types.js +++ b/workers/loc.api/di/types.js @@ -67,5 +67,6 @@ module.exports = { SyncUserStepManager: Symbol.for('SyncUserStepManager'), SyncUserStepData: Symbol.for('SyncUserStepData'), SyncUserStepDataFactory: Symbol.for('SyncUserStepDataFactory'), - WeightedAveragesReport: Symbol.for('WeightedAveragesReport') + WeightedAveragesReport: Symbol.for('WeightedAveragesReport'), + WeightedAveragesReportCsvWriter: Symbol.for('WeightedAveragesReportCsvWriter') } From 8b5eaf01028cd8b35adc46c66d34b400eaf214df Mon Sep 17 00:00:00 2001 From: Vladimir Voronkov Date: Wed, 4 Jan 2023 12:51:04 +0200 Subject: [PATCH 10/18] Add WeightedAveragesReportCsvWriter service to di --- workers/loc.api/di/app.deps.js | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/workers/loc.api/di/app.deps.js b/workers/loc.api/di/app.deps.js index 119802ead..eebec41dd 100644 --- a/workers/loc.api/di/app.deps.js +++ b/workers/loc.api/di/app.deps.js @@ -90,7 +90,8 @@ const CurrencyConverter = require('../sync/currency.converter') const CsvJobData = require('../generate-csv/csv.job.data') const { fullSnapshotReportCsvWriter, - fullTaxReportCsvWriter + fullTaxReportCsvWriter, + weightedAveragesReportCsvWriter } = require('../generate-csv/csv-writer') const FullTaxReport = require('../sync/full.tax.report') const WeightedAveragesReport = require('../sync/weighted.averages.report') @@ -360,6 +361,16 @@ module.exports = ({ ] ) ) + bind(TYPES.WeightedAveragesReportCsvWriter) + .toConstantValue( + bindDepsToFn( + weightedAveragesReportCsvWriter, + [ + TYPES.RService, + TYPES.GetDataFromApi + ] + ) + ) bind(TYPES.FullTaxReport) .to(FullTaxReport) bind(TYPES.WeightedAveragesReport) From 5d352fba183dfad9f0e6ec7b9172f8dcaf0f2dc3 Mon Sep 17 00:00:00 2001 From: Vladimir Voronkov Date: Wed, 4 Jan 2023 12:58:48 +0200 Subject: [PATCH 11/18] Create weighted averages report csv writer --- .../loc.api/generate-csv/csv-writer/index.js | 6 +- .../weighted-averages-report-csv-writer.js | 77 +++++++++++++++++++ 2 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 workers/loc.api/generate-csv/csv-writer/weighted-averages-report-csv-writer.js diff --git a/workers/loc.api/generate-csv/csv-writer/index.js b/workers/loc.api/generate-csv/csv-writer/index.js index 1ef83bf4f..f9a8660f5 100644 --- a/workers/loc.api/generate-csv/csv-writer/index.js +++ b/workers/loc.api/generate-csv/csv-writer/index.js @@ -6,8 +6,12 @@ const fullSnapshotReportCsvWriter = require( const fullTaxReportCsvWriter = require( './full-tax-report-csv-writer' ) +const weightedAveragesReportCsvWriter = require( + './weighted-averages-report-csv-writer' +) module.exports = { fullSnapshotReportCsvWriter, - fullTaxReportCsvWriter + fullTaxReportCsvWriter, + weightedAveragesReportCsvWriter } diff --git a/workers/loc.api/generate-csv/csv-writer/weighted-averages-report-csv-writer.js b/workers/loc.api/generate-csv/csv-writer/weighted-averages-report-csv-writer.js new file mode 100644 index 000000000..08696a7b0 --- /dev/null +++ b/workers/loc.api/generate-csv/csv-writer/weighted-averages-report-csv-writer.js @@ -0,0 +1,77 @@ +'use strict' + +const { pipeline } = require('stream') +const { stringify } = require('csv') + +const { + write +} = require('bfx-report/workers/loc.api/queue/write-data-to-stream/helpers') + +const nope = () => {} + +module.exports = ( + rService, + getDataFromApi +) => async ( + wStream, + jobData +) => { + const queue = rService.ctx.lokue_aggregator.q + const { + args, + columnsCsv, + formatSettings, + name + } = jobData ?? {} + const { params } = args ?? {} + + queue.emit('progress', 0) + + if (typeof jobData === 'string') { + const stringifier = stringify( + { columns: ['mess'] } + ) + + pipeline(stringifier, wStream, nope) + write([{ mess: jobData }], stringifier) + queue.emit('progress', 100) + stringifier.end() + + return + } + + wStream.setMaxListeners(50) + + const headerStringifier = stringify( + { columns: ['empty', 'final', 'empty', 'buying', 'empty', 'selling', 'empty'] } + ) + const resStringifier = stringify({ + header: true, + columns: columnsCsv + }) + + pipeline(headerStringifier, wStream, nope) + pipeline(resStringifier, wStream, nope) + + const res = await getDataFromApi({ + getData: rService[name].bind(rService), + args, + callerName: 'CSV_WRITER' + }) + + write( + [{ empty: '', final: 'FINAL', buying: 'BUYING', selling: 'SELLING' }], + headerStringifier + ) + write( + res, + resStringifier, + formatSettings, + params + ) + + queue.emit('progress', 100) + + headerStringifier.end() + resStringifier.end() +} From eb01899888f5cf96e4a5a092e4338d446c42ec56 Mon Sep 17 00:00:00 2001 From: Vladimir Voronkov Date: Wed, 4 Jan 2023 13:00:34 +0200 Subject: [PATCH 12/18] Fix csv job data for weighted averages report --- workers/loc.api/generate-csv/csv.job.data.js | 24 ++++++++------------ 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/workers/loc.api/generate-csv/csv.job.data.js b/workers/loc.api/generate-csv/csv.job.data.js index ac34621a1..efd175201 100644 --- a/workers/loc.api/generate-csv/csv.job.data.js +++ b/workers/loc.api/generate-csv/csv.job.data.js @@ -21,20 +21,20 @@ const depsTypes = (TYPES) => [ TYPES.RService, TYPES.FullSnapshotReportCsvWriter, TYPES.FullTaxReportCsvWriter, - TYPES.WeightedAveragesReportCsv + TYPES.WeightedAveragesReportCsvWriter ] class CsvJobData extends BaseCsvJobData { constructor ( rService, fullSnapshotReportCsvWriter, fullTaxReportCsvWriter, - weightedAveragesReportCsv + weightedAveragesReportCsvWriter ) { super(rService) this.fullSnapshotReportCsvWriter = fullSnapshotReportCsvWriter this.fullTaxReportCsvWriter = fullTaxReportCsvWriter - this.weightedAveragesReportCsv = weightedAveragesReportCsv + this.weightedAveragesReportCsvWriter = weightedAveragesReportCsvWriter } _addColumnsBySchema (columnsCsv = {}, schema = {}) { @@ -697,18 +697,12 @@ class CsvJobData extends BaseCsvJobData { args: csvArgs, columnsCsv: { symbol: 'PAIR', - final: { - weightedPrice: 'WEIGHTED PRICE', - amount: 'AMOUNT' - }, - buying: { - weightedPrice: 'WEIGHTED PRICE', - amount: 'AMOUNT' - }, - selling: { - weightedPrice: 'WEIGHTED PRICE', - amount: 'AMOUNT' - } + finalWeightedPrice: 'WEIGHTED PRICE', + finalAmount: 'AMOUNT', + buyingWeightedPrice: 'WEIGHTED PRICE', + buyingAmount: 'AMOUNT', + sellingWeightedPrice: 'WEIGHTED PRICE', + sellingAmount: 'AMOUNT' }, formatSettings: { symbol: 'symbol' From e21c15b2fbc0d315242966568e09bb2c9d1fc089 Mon Sep 17 00:00:00 2001 From: Vladimir Voronkov Date: Thu, 5 Jan 2023 07:54:02 +0200 Subject: [PATCH 13/18] Improve csv column order --- workers/loc.api/generate-csv/csv.job.data.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/workers/loc.api/generate-csv/csv.job.data.js b/workers/loc.api/generate-csv/csv.job.data.js index efd175201..a4128fd1f 100644 --- a/workers/loc.api/generate-csv/csv.job.data.js +++ b/workers/loc.api/generate-csv/csv.job.data.js @@ -697,12 +697,12 @@ class CsvJobData extends BaseCsvJobData { args: csvArgs, columnsCsv: { symbol: 'PAIR', - finalWeightedPrice: 'WEIGHTED PRICE', - finalAmount: 'AMOUNT', buyingWeightedPrice: 'WEIGHTED PRICE', buyingAmount: 'AMOUNT', sellingWeightedPrice: 'WEIGHTED PRICE', - sellingAmount: 'AMOUNT' + sellingAmount: 'AMOUNT', + cumulativeWeightedPrice: 'WEIGHTED PRICE', + cumulativeAmount: 'AMOUNT' }, formatSettings: { symbol: 'symbol' From 45e53b4a538adafa0d57f3fb4c5cd90672383326 Mon Sep 17 00:00:00 2001 From: Vladimir Voronkov Date: Thu, 5 Jan 2023 07:54:29 +0200 Subject: [PATCH 14/18] Improve csv key-headers column order --- .../csv-writer/weighted-averages-report-csv-writer.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/workers/loc.api/generate-csv/csv-writer/weighted-averages-report-csv-writer.js b/workers/loc.api/generate-csv/csv-writer/weighted-averages-report-csv-writer.js index 08696a7b0..e620ee95c 100644 --- a/workers/loc.api/generate-csv/csv-writer/weighted-averages-report-csv-writer.js +++ b/workers/loc.api/generate-csv/csv-writer/weighted-averages-report-csv-writer.js @@ -43,7 +43,7 @@ module.exports = ( wStream.setMaxListeners(50) const headerStringifier = stringify( - { columns: ['empty', 'final', 'empty', 'buying', 'empty', 'selling', 'empty'] } + { columns: ['empty', 'buy', 'empty', 'sell', 'empty', 'cumulative', 'empty'] } ) const resStringifier = stringify({ header: true, @@ -60,7 +60,7 @@ module.exports = ( }) write( - [{ empty: '', final: 'FINAL', buying: 'BUYING', selling: 'SELLING' }], + [{ empty: '', buy: 'Buy', sell: 'Sell', cumulative: 'Cumulative' }], headerStringifier ) write( From c27fa734b0137384d7103b11770933f9935f84b4 Mon Sep 17 00:00:00 2001 From: Vladimir Voronkov Date: Thu, 5 Jan 2023 09:54:37 +0200 Subject: [PATCH 15/18] Add ability to fetch trades for weighted averages report --- .../sync/weighted.averages.report/index.js | 90 +++++++++++++++++-- 1 file changed, 81 insertions(+), 9 deletions(-) diff --git a/workers/loc.api/sync/weighted.averages.report/index.js b/workers/loc.api/sync/weighted.averages.report/index.js index 776039fbd..e687dce91 100644 --- a/workers/loc.api/sync/weighted.averages.report/index.js +++ b/workers/loc.api/sync/weighted.averages.report/index.js @@ -5,17 +5,23 @@ const { decorateInjectable } = require('../../di/utils') const depsTypes = (TYPES) => [ TYPES.DAO, TYPES.Authenticator, - TYPES.Trades + TYPES.SyncSchema, + TYPES.ALLOWED_COLLS ] class WeightedAveragesReport { constructor ( dao, authenticator, - trades + syncSchema, + ALLOWED_COLLS ) { this.dao = dao this.authenticator = authenticator - this.trades = trades + this.syncSchema = syncSchema + this.ALLOWED_COLLS = ALLOWED_COLLS + + this.tradesModel = this.syncSchema.getModelsMap() + .get(this.ALLOWED_COLLS.TRADES) } async getWeightedAveragesReport (args = {}) { @@ -23,16 +29,82 @@ class WeightedAveragesReport { auth = {}, params = {} } = args ?? {} + + const user = await this.authenticator + .verifyRequestUser({ auth }) + const { start = 0, end = Date.now(), - symbol = [] + symbol: _symbol = [] } = params ?? {} - const user = await this.authenticator - .verifyRequestUser({ auth }) - const symbolArr = Array.isArray(symbol) - ? symbol - : [symbol] + const symbolArr = Array.isArray(_symbol) + ? _symbol + : [_symbol] + const symbol = symbolArr.filter((s) => ( + s && typeof s === 'string' + )) + + const trades = await this._getTrades({ + user, + start, + end, + symbol + }) + + // TODO: example returned data structure + return [ + { + symbol: 'tBTCUSD', + buyingWeightedPrice: 123.321, + buyingAmount: 0.321, + sellingWeightedPrice: 123.321, + sellingAmount: 0.321, + cumulativeWeightedPrice: 123.321, + cumulativeAmount: 0.321 + }, + { + symbol: 'tETHUSD', + buyingWeightedPrice: 321.123, + buyingAmount: 0.123, + sellingWeightedPrice: 321.123, + sellingAmount: 0.123, + cumulativeWeightedPrice: 321.123, + cumulativeAmount: 0.123 + } + ] + } + + async _getTrades (args) { + const { + user = {}, + start = 0, + end = Date.now(), + symbol = [] + } = args ?? {} + + const symbFilter = ( + Array.isArray(symbol) && + symbol.length !== 0 + ) + ? { $in: { symbol } } + : {} + + return this.dao.getElemsInCollBy( + this.ALLOWED_COLLS.TRADES, + { + filter: { + user_id: user._id, + $lte: { mtsCreate: end }, + $gte: { mtsCreate: start }, + ...symbFilter + }, + sort: [['mtsCreate', -1]], + projection: this.tradesModel, + exclude: ['user_id'], + isExcludePrivate: true + } + ) } } From d337366a49a958e69647ae4a33a355cfabfc2366 Mon Sep 17 00:00:00 2001 From: Vladimir Voronkov Date: Thu, 5 Jan 2023 14:05:06 +0200 Subject: [PATCH 16/18] Implement trades weighted price calc --- .../sync/weighted.averages.report/index.js | 125 +++++++++++++++--- 1 file changed, 104 insertions(+), 21 deletions(-) diff --git a/workers/loc.api/sync/weighted.averages.report/index.js b/workers/loc.api/sync/weighted.averages.report/index.js index e687dce91..fa99fb806 100644 --- a/workers/loc.api/sync/weighted.averages.report/index.js +++ b/workers/loc.api/sync/weighted.averages.report/index.js @@ -51,28 +51,9 @@ class WeightedAveragesReport { end, symbol }) + const calcedTrades = this._calcTrades(trades) - // TODO: example returned data structure - return [ - { - symbol: 'tBTCUSD', - buyingWeightedPrice: 123.321, - buyingAmount: 0.321, - sellingWeightedPrice: 123.321, - sellingAmount: 0.321, - cumulativeWeightedPrice: 123.321, - cumulativeAmount: 0.321 - }, - { - symbol: 'tETHUSD', - buyingWeightedPrice: 321.123, - buyingAmount: 0.123, - sellingWeightedPrice: 321.123, - sellingAmount: 0.123, - cumulativeWeightedPrice: 321.123, - cumulativeAmount: 0.123 - } - ] + return calcedTrades } async _getTrades (args) { @@ -106,6 +87,108 @@ class WeightedAveragesReport { } ) } + + _calcTrades (trades = []) { + const symbResMap = new Map() + + for (const trade of trades) { + const { + symbol, + execAmount, + execPrice + } = trade ?? {} + + if ( + !symbol || + typeof symbol !== 'string' || + !Number.isFinite(execAmount) || + execAmount === 0 || + !Number.isFinite(execPrice) || + execPrice === 0 + ) { + continue + } + + const isBuying = execAmount > 0 + const spent = execAmount * execPrice + + const existedSymbRes = symbResMap.get(symbol) + const { + sumSpent: _sumSpent = 0, + sumAmount: _sumAmount = 0, + sumBuyingSpent: _sumBuyingSpent = 0, + sumBuyingAmount: _sumBuyingAmount = 0, + sumSellingSpent: _sumSellingSpent = 0, + sumSellingAmount: _sumSellingAmount = 0 + } = existedSymbRes ?? {} + + const sumSpent = Number.isFinite(spent) + ? _sumSpent + spent + : _sumSpent + const sumAmount = _sumAmount + execAmount + const sumBuyingSpent = ( + isBuying && + Number.isFinite(spent) + ) + ? _sumBuyingSpent + spent + : _sumBuyingSpent + const sumBuyingAmount = isBuying + ? _sumBuyingAmount + execAmount + : _sumBuyingAmount + const sumSellingSpent = ( + !isBuying && + Number.isFinite(spent) + ) + ? _sumSellingSpent + spent + : _sumSellingSpent + const sumSellingAmount = !isBuying + ? _sumSellingAmount + execAmount + : _sumSellingAmount + + symbResMap.set(symbol, { + sumSpent, + sumAmount, + sumBuyingSpent, + sumBuyingAmount, + sumSellingSpent, + sumSellingAmount, + + buyingWeightedPrice: sumBuyingAmount === 0 + ? 0 + : sumBuyingSpent / sumBuyingAmount, + buyingAmount: sumBuyingAmount, + sellingWeightedPrice: sumSellingAmount === 0 + ? 0 + : sumSellingSpent / sumSellingAmount, + sellingAmount: sumSellingAmount, + cumulativeWeightedPrice: sumAmount === 0 + ? 0 + : sumSpent / sumAmount, + cumulativeAmount: sumAmount + }) + } + + return [...symbResMap].map(([symbol, val]) => { + const { + buyingWeightedPrice = 0, + buyingAmount = 0, + sellingWeightedPrice = 0, + sellingAmount = 0, + cumulativeWeightedPrice = 0, + cumulativeAmount = 0 + } = val ?? {} + + return { + symbol, + buyingWeightedPrice, + buyingAmount, + sellingWeightedPrice, + sellingAmount, + cumulativeWeightedPrice, + cumulativeAmount + } + }) + } } decorateInjectable(WeightedAveragesReport, depsTypes) From db7aea232ac6dce1f54f4819ca64138ea5e35f1e Mon Sep 17 00:00:00 2001 From: Vladimir Voronkov Date: Fri, 6 Jan 2023 09:45:07 +0200 Subject: [PATCH 17/18] Add test coverage for getWeightedAveragesReport endpoint --- ...itional-api-sync-mode-sqlite-test-cases.js | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/test/test-cases/additional-api-sync-mode-sqlite-test-cases.js b/test/test-cases/additional-api-sync-mode-sqlite-test-cases.js index d692479aa..5ede2f25f 100644 --- a/test/test-cases/additional-api-sync-mode-sqlite-test-cases.js +++ b/test/test-cases/additional-api-sync-mode-sqlite-test-cases.js @@ -554,6 +554,50 @@ module.exports = ( } }) + it('it should be successfully performed by the getWeightedAveragesReport method', async function () { + this.timeout(120000) + + const paramsArr = [ + { end, start }, + { + end, + start: end - (10 * 60 * 60 * 1000), + symbol: ['tBTCUSD'] + } + ] + + for (const params of paramsArr) { + const res = await agent + .post(`${basePath}/json-rpc`) + .type('json') + .send({ + auth, + method: 'getWeightedAveragesReport', + params, + id: 5 + }) + .expect('Content-Type', /json/) + .expect(200) + + assert.isObject(res.body) + assert.propertyVal(res.body, 'id', 5) + assert.isArray(res.body.result) + + const resItem = res.body.result[0] + + assert.isObject(resItem) + assert.containsAllKeys(resItem, [ + 'symbol', + 'buyingWeightedPrice', + 'buyingAmount', + 'sellingWeightedPrice', + 'sellingAmount', + 'cumulativeWeightedPrice', + 'cumulativeAmount' + ]) + } + }) + it('it should be successfully performed by the getMultipleCsv method', async function () { this.timeout(60000) From 6ffbfc884b1d25ffc42d322c4a6903be726e3b26 Mon Sep 17 00:00:00 2001 From: Vladimir Voronkov Date: Fri, 6 Jan 2023 09:56:55 +0200 Subject: [PATCH 18/18] Add test coverage for getWeightedAveragesReportCsv endpoint --- ...itional-api-sync-mode-sqlite-test-cases.js | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/test/test-cases/additional-api-sync-mode-sqlite-test-cases.js b/test/test-cases/additional-api-sync-mode-sqlite-test-cases.js index 5ede2f25f..8f8153d9d 100644 --- a/test/test-cases/additional-api-sync-mode-sqlite-test-cases.js +++ b/test/test-cases/additional-api-sync-mode-sqlite-test-cases.js @@ -983,4 +983,29 @@ module.exports = ( await testMethodOfGettingCsv(procPromise, aggrPromise, res) }) + + it('it should be successfully performed by the getWeightedAveragesReportCsv method', async function () { + this.timeout(60000) + + const procPromise = queueToPromise(params.processorQueue) + const aggrPromise = queueToPromise(params.aggregatorQueue) + + const res = await agent + .post(`${basePath}/json-rpc`) + .type('json') + .send({ + auth, + method: 'getWeightedAveragesReportCsv', + params: { + end, + start, + email + }, + id: 5 + }) + .expect('Content-Type', /json/) + .expect(200) + + await testMethodOfGettingCsv(procPromise, aggrPromise, res) + }) }