@tradejs/cli 2.0.1 → 2.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +293 -58
- package/dist/lib/aiPocketSearch.js +18 -0
- package/dist/lib/aiTrainCharts.js +49 -2
- package/dist/lib/aiTrainMetrics.js +49 -2
- package/dist/lib/aiTrainResearch.js +58 -3
- package/dist/lib/derivativesContextBackfill.js +143 -32
- package/dist/lib/marketContextPrepare.js +141 -32
- package/dist/lib/runtimeTradeSync.js +22 -15
- package/dist/scripts/aiExport.js +2 -1
- package/dist/scripts/aiExportSelect.js +2 -1
- package/dist/scripts/aiPocketSearch.js +67 -2
- package/dist/scripts/aiTrain.js +76 -3
- package/dist/scripts/backtest.js +141 -32
- package/dist/scripts/derivativesIngestCoinalyzeAll.js +30 -0
- package/dist/scripts/mlExport.js +2 -1
- package/dist/scripts/mlExportSelect.js +2 -1
- package/dist/scripts/mlTrainLatestSelect.js +2 -1
- package/dist/scripts/replay.js +161 -47
- package/dist/scripts/replayRunner.js +161 -47
- package/dist/scripts/resolveExportStrategy.js +2 -1
- package/dist/scripts/runtimeParity.js +141 -32
- package/dist/scripts/selectStrategy.js +2 -1
- package/dist/scripts/signals.js +141 -32
- package/dist/scripts/signalsDaemon.js +141 -32
- package/dist/scripts/signalsSummary.js +21 -17
- package/package.json +9 -9
package/dist/scripts/replay.js
CHANGED
|
@@ -3224,6 +3224,38 @@ var resolveDerivativesContextMissingFetchFromMs = (params) => {
|
|
|
3224
3224
|
return null;
|
|
3225
3225
|
};
|
|
3226
3226
|
var resolveDerivativesContextFetchFromMs = (params) => resolveDerivativesContextMissingFetchFromMs(params) ?? (params.refreshClosedTail ? params.toMs : null);
|
|
3227
|
+
var resolveDerivativesContextRequiredFetchFromMs = (params) => {
|
|
3228
|
+
const dataCoverageFromMs = params.dataCoverageKeyExists ? null : params.mode === "signals" ? params.fromMs : resolveDerivativesContextMissingCoverageFetchFromMs({
|
|
3229
|
+
ranges: params.dataCoverageRanges,
|
|
3230
|
+
fromMs: params.fromMs,
|
|
3231
|
+
toMs: params.toMs,
|
|
3232
|
+
intervalMs: params.intervalMs
|
|
3233
|
+
});
|
|
3234
|
+
const edgesFromMs = dataCoverageFromMs == null ? null : resolveDerivativesContextFetchFromMs({
|
|
3235
|
+
edges: params.edges,
|
|
3236
|
+
fromMs: params.fromMs,
|
|
3237
|
+
toMs: params.toMs,
|
|
3238
|
+
intervalMs: params.intervalMs,
|
|
3239
|
+
refreshClosedTail: params.mode === "signals"
|
|
3240
|
+
});
|
|
3241
|
+
const dataFetchFromMs = dataCoverageFromMs != null && edgesFromMs != null ? Math.max(dataCoverageFromMs, edgesFromMs) : null;
|
|
3242
|
+
const confirmedLiquidationWindow = (0, import_indicators.resolveCoinalyzeConfirmedIntradayCoverage)({
|
|
3243
|
+
interval: params.interval,
|
|
3244
|
+
fromMs: params.fromMs,
|
|
3245
|
+
toMs: params.toMs,
|
|
3246
|
+
nowMs: params.nowMs
|
|
3247
|
+
});
|
|
3248
|
+
const liquidationFetchFromMs = confirmedLiquidationWindow ? resolveDerivativesContextMissingCoverageFetchFromMs({
|
|
3249
|
+
ranges: params.liquidationCoverageRanges,
|
|
3250
|
+
fromMs: confirmedLiquidationWindow.fromMs,
|
|
3251
|
+
toMs: confirmedLiquidationWindow.toMs,
|
|
3252
|
+
intervalMs: params.intervalMs
|
|
3253
|
+
}) : null;
|
|
3254
|
+
const fetchStarts = [dataFetchFromMs, liquidationFetchFromMs].filter(
|
|
3255
|
+
(value) => value != null
|
|
3256
|
+
);
|
|
3257
|
+
return fetchStarts.length ? Math.min(...fetchStarts) : null;
|
|
3258
|
+
};
|
|
3227
3259
|
var countBackfillWindows = (params) => {
|
|
3228
3260
|
let count = 0;
|
|
3229
3261
|
let cursor = params.fromMs;
|
|
@@ -3559,7 +3591,8 @@ var backfillDerivativesContext = async (params, enabled, mode) => {
|
|
|
3559
3591
|
mode,
|
|
3560
3592
|
startMs,
|
|
3561
3593
|
endMs,
|
|
3562
|
-
preloadStartMs: params.preloadStartMs
|
|
3594
|
+
preloadStartMs: params.preloadStartMs,
|
|
3595
|
+
nowMs: Date.now()
|
|
3563
3596
|
});
|
|
3564
3597
|
if (safeEndMs <= fromMs) {
|
|
3565
3598
|
return skippedBackfillResult2();
|
|
@@ -3593,15 +3626,33 @@ var backfillDerivativesContext = async (params, enabled, mode) => {
|
|
|
3593
3626
|
);
|
|
3594
3627
|
const coverageKeysByInterval = /* @__PURE__ */ new Map();
|
|
3595
3628
|
const coverageRangesByInterval = /* @__PURE__ */ new Map();
|
|
3629
|
+
const liquidationCoverageRangesByInterval = /* @__PURE__ */ new Map();
|
|
3630
|
+
const coverageNowMs = Date.now();
|
|
3596
3631
|
await Promise.all(
|
|
3597
3632
|
intervalWindows.map(async (window2) => {
|
|
3598
|
-
const
|
|
3599
|
-
source: "coinalyze",
|
|
3600
|
-
symbols,
|
|
3633
|
+
const confirmedLiquidationWindow = (0, import_indicators.resolveCoinalyzeConfirmedIntradayCoverage)({
|
|
3601
3634
|
interval: window2.interval,
|
|
3602
3635
|
fromMs: window2.fromMs,
|
|
3603
|
-
toMs: window2.toMs
|
|
3636
|
+
toMs: window2.toMs,
|
|
3637
|
+
nowMs: coverageNowMs
|
|
3604
3638
|
});
|
|
3639
|
+
const [coverageRows, liquidationCoverageRows] = await Promise.all([
|
|
3640
|
+
(0, import_timescale2.getDerivativesBackfillCoverage)({
|
|
3641
|
+
source: "coinalyze",
|
|
3642
|
+
symbols,
|
|
3643
|
+
interval: window2.interval,
|
|
3644
|
+
fromMs: window2.fromMs,
|
|
3645
|
+
toMs: window2.toMs
|
|
3646
|
+
}),
|
|
3647
|
+
confirmedLiquidationWindow ? (0, import_timescale2.getDerivativesMetricCoverage)({
|
|
3648
|
+
source: "coinalyze",
|
|
3649
|
+
metric: "liquidation",
|
|
3650
|
+
symbols,
|
|
3651
|
+
interval: window2.interval,
|
|
3652
|
+
fromMs: confirmedLiquidationWindow.fromMs,
|
|
3653
|
+
toMs: confirmedLiquidationWindow.toMs
|
|
3654
|
+
}) : Promise.resolve([])
|
|
3655
|
+
]);
|
|
3605
3656
|
coverageKeysByInterval.set(
|
|
3606
3657
|
window2.interval,
|
|
3607
3658
|
new Set(
|
|
@@ -3623,6 +3674,17 @@ var backfillDerivativesContext = async (params, enabled, mode) => {
|
|
|
3623
3674
|
rangesBySymbol.set(symbol, ranges);
|
|
3624
3675
|
}
|
|
3625
3676
|
coverageRangesByInterval.set(window2.interval, rangesBySymbol);
|
|
3677
|
+
const liquidationRangesBySymbol = /* @__PURE__ */ new Map();
|
|
3678
|
+
for (const row of liquidationCoverageRows) {
|
|
3679
|
+
const symbol = row.symbol.toUpperCase();
|
|
3680
|
+
const ranges = liquidationRangesBySymbol.get(symbol) ?? [];
|
|
3681
|
+
ranges.push({ fromMs: row.fromMs, toMs: row.toMs });
|
|
3682
|
+
liquidationRangesBySymbol.set(symbol, ranges);
|
|
3683
|
+
}
|
|
3684
|
+
liquidationCoverageRangesByInterval.set(
|
|
3685
|
+
window2.interval,
|
|
3686
|
+
liquidationRangesBySymbol
|
|
3687
|
+
);
|
|
3626
3688
|
})
|
|
3627
3689
|
);
|
|
3628
3690
|
const cachedWindows = intervalWindows.reduce(
|
|
@@ -3647,7 +3709,7 @@ var backfillDerivativesContext = async (params, enabled, mode) => {
|
|
|
3647
3709
|
(symbol) => backfillWindows.every((backfillWindow) => {
|
|
3648
3710
|
const normalizedSymbol = symbol.toUpperCase();
|
|
3649
3711
|
const coverageRanges = coverageRangesByInterval.get(window2.interval)?.get(normalizedSymbol) ?? [];
|
|
3650
|
-
|
|
3712
|
+
const dataCovered = hasDerivativesWindowCoverage({
|
|
3651
3713
|
edges: edgesBySymbol?.get(normalizedSymbol),
|
|
3652
3714
|
fromMs: backfillWindow.fromMs,
|
|
3653
3715
|
toMs: backfillWindow.toMs
|
|
@@ -3664,6 +3726,19 @@ var backfillDerivativesContext = async (params, enabled, mode) => {
|
|
|
3664
3726
|
toMs: backfillWindow.toMs
|
|
3665
3727
|
})
|
|
3666
3728
|
);
|
|
3729
|
+
const confirmedLiquidationWindow = (0, import_indicators.resolveCoinalyzeConfirmedIntradayCoverage)({
|
|
3730
|
+
interval: window2.interval,
|
|
3731
|
+
fromMs: backfillWindow.fromMs,
|
|
3732
|
+
toMs: backfillWindow.toMs,
|
|
3733
|
+
nowMs: coverageNowMs
|
|
3734
|
+
});
|
|
3735
|
+
const liquidationCovered = confirmedLiquidationWindow == null || resolveDerivativesContextMissingCoverageFetchFromMs({
|
|
3736
|
+
ranges: liquidationCoverageRangesByInterval.get(window2.interval)?.get(normalizedSymbol) ?? [],
|
|
3737
|
+
fromMs: confirmedLiquidationWindow.fromMs,
|
|
3738
|
+
toMs: confirmedLiquidationWindow.toMs,
|
|
3739
|
+
intervalMs: window2.intervalMs
|
|
3740
|
+
}) == null;
|
|
3741
|
+
return dataCovered && liquidationCovered;
|
|
3667
3742
|
})
|
|
3668
3743
|
);
|
|
3669
3744
|
});
|
|
@@ -3748,6 +3823,11 @@ var backfillDerivativesContext = async (params, enabled, mode) => {
|
|
|
3748
3823
|
coverageKeysByInterval.set(interval, coverageKeys);
|
|
3749
3824
|
const coverageRangesBySymbol = coverageRangesByInterval.get(interval) ?? /* @__PURE__ */ new Map();
|
|
3750
3825
|
coverageRangesByInterval.set(interval, coverageRangesBySymbol);
|
|
3826
|
+
const liquidationCoverageRangesBySymbol = liquidationCoverageRangesByInterval.get(interval) ?? /* @__PURE__ */ new Map();
|
|
3827
|
+
liquidationCoverageRangesByInterval.set(
|
|
3828
|
+
interval,
|
|
3829
|
+
liquidationCoverageRangesBySymbol
|
|
3830
|
+
);
|
|
3751
3831
|
for (let batchIdx = 0; batchIdx < symbolBatches.length; batchIdx += 1) {
|
|
3752
3832
|
const batch = symbolBatches[batchIdx];
|
|
3753
3833
|
let cursor = window2.fromMs;
|
|
@@ -3760,33 +3840,25 @@ var backfillDerivativesContext = async (params, enabled, mode) => {
|
|
|
3760
3840
|
fromMs: cursor,
|
|
3761
3841
|
toMs
|
|
3762
3842
|
});
|
|
3763
|
-
if (coverageKeys.has(key)) {
|
|
3764
|
-
return null;
|
|
3765
|
-
}
|
|
3766
3843
|
const normalizedSymbol = item.symbol.toUpperCase();
|
|
3767
|
-
const
|
|
3768
|
-
|
|
3769
|
-
|
|
3770
|
-
|
|
3771
|
-
|
|
3772
|
-
|
|
3773
|
-
|
|
3774
|
-
|
|
3775
|
-
|
|
3776
|
-
|
|
3777
|
-
|
|
3778
|
-
|
|
3779
|
-
|
|
3780
|
-
|
|
3781
|
-
|
|
3782
|
-
refreshClosedTail: mode === "signals"
|
|
3783
|
-
});
|
|
3784
|
-
if (edgesFromMs == null) {
|
|
3785
|
-
return null;
|
|
3786
|
-
}
|
|
3844
|
+
const requiredFromMs = resolveDerivativesContextRequiredFetchFromMs(
|
|
3845
|
+
{
|
|
3846
|
+
mode,
|
|
3847
|
+
interval,
|
|
3848
|
+
intervalMs,
|
|
3849
|
+
fromMs: cursor,
|
|
3850
|
+
toMs,
|
|
3851
|
+
nowMs: coverageNowMs,
|
|
3852
|
+
dataCoverageKeyExists: coverageKeys.has(key),
|
|
3853
|
+
dataCoverageRanges: coverageRangesBySymbol.get(normalizedSymbol),
|
|
3854
|
+
liquidationCoverageRanges: liquidationCoverageRangesBySymbol.get(normalizedSymbol),
|
|
3855
|
+
edges: edgesBySymbol.get(normalizedSymbol)
|
|
3856
|
+
}
|
|
3857
|
+
);
|
|
3858
|
+
if (requiredFromMs == null) return null;
|
|
3787
3859
|
return {
|
|
3788
3860
|
item,
|
|
3789
|
-
fromMs:
|
|
3861
|
+
fromMs: requiredFromMs
|
|
3790
3862
|
};
|
|
3791
3863
|
}).filter(
|
|
3792
3864
|
(item) => item != null
|
|
@@ -3811,6 +3883,7 @@ var backfillDerivativesContext = async (params, enabled, mode) => {
|
|
|
3811
3883
|
);
|
|
3812
3884
|
let rows = [];
|
|
3813
3885
|
let missingClosedSymbols = [];
|
|
3886
|
+
let liquidationRowsByMarket = /* @__PURE__ */ new Map();
|
|
3814
3887
|
for (let attempt = 1; attempt <= maxClosedBarAttempts; attempt += 1) {
|
|
3815
3888
|
const oiMap = await fetchMetricBatch({
|
|
3816
3889
|
endpoint: oiPath,
|
|
@@ -3830,7 +3903,7 @@ var backfillDerivativesContext = async (params, enabled, mode) => {
|
|
|
3830
3903
|
fromMs: group.fromMs,
|
|
3831
3904
|
toMs
|
|
3832
3905
|
});
|
|
3833
|
-
|
|
3906
|
+
liquidationRowsByMarket = await fetchMetricBatch({
|
|
3834
3907
|
endpoint: liqPath,
|
|
3835
3908
|
metric: "liq",
|
|
3836
3909
|
marketSymbols,
|
|
@@ -3845,7 +3918,7 @@ var backfillDerivativesContext = async (params, enabled, mode) => {
|
|
|
3845
3918
|
symbol: item.symbol,
|
|
3846
3919
|
oiRaw: oiMap.get(marketSymbol) ?? [],
|
|
3847
3920
|
fundingRaw: fundingMap.get(marketSymbol) ?? [],
|
|
3848
|
-
liqRaw:
|
|
3921
|
+
liqRaw: liquidationRowsByMarket.get(marketSymbol) ?? []
|
|
3849
3922
|
});
|
|
3850
3923
|
return (0, import_indicators.coinalyzePointsToRows)(points, interval, "coinalyze");
|
|
3851
3924
|
});
|
|
@@ -3868,6 +3941,42 @@ var backfillDerivativesContext = async (params, enabled, mode) => {
|
|
|
3868
3941
|
await (0, import_timescale2.upsertDerivatives)(rows);
|
|
3869
3942
|
totalRows += rows.length;
|
|
3870
3943
|
}
|
|
3944
|
+
const confirmedLiquidationWindow = (0, import_indicators.resolveCoinalyzeConfirmedIntradayCoverage)({
|
|
3945
|
+
interval,
|
|
3946
|
+
fromMs: group.fromMs,
|
|
3947
|
+
toMs,
|
|
3948
|
+
nowMs: coverageNowMs
|
|
3949
|
+
});
|
|
3950
|
+
if (confirmedLiquidationWindow) {
|
|
3951
|
+
const metricCoverageRows = missingBatch.map((item) => {
|
|
3952
|
+
const marketSymbol = item.marketSymbol.toUpperCase();
|
|
3953
|
+
const eventRowsCount = (liquidationRowsByMarket.get(marketSymbol) ?? []).filter((point) => {
|
|
3954
|
+
const timestamp = (0, import_indicators.toCoinalyzeTimestampMs)(
|
|
3955
|
+
point.t ?? point.ts ?? point.time ?? point.timestamp
|
|
3956
|
+
);
|
|
3957
|
+
return timestamp != null && timestamp >= confirmedLiquidationWindow.fromMs && timestamp <= confirmedLiquidationWindow.toMs;
|
|
3958
|
+
}).length;
|
|
3959
|
+
return {
|
|
3960
|
+
source: "coinalyze",
|
|
3961
|
+
metric: "liquidation",
|
|
3962
|
+
symbol: item.symbol,
|
|
3963
|
+
interval,
|
|
3964
|
+
fromMs: confirmedLiquidationWindow.fromMs,
|
|
3965
|
+
toMs: confirmedLiquidationWindow.toMs,
|
|
3966
|
+
eventRowsCount
|
|
3967
|
+
};
|
|
3968
|
+
});
|
|
3969
|
+
await (0, import_timescale2.applyDerivativesMetricCoverage)(metricCoverageRows);
|
|
3970
|
+
for (const coverageRow of metricCoverageRows) {
|
|
3971
|
+
const symbol = coverageRow.symbol.toUpperCase();
|
|
3972
|
+
const ranges = liquidationCoverageRangesBySymbol.get(symbol) ?? [];
|
|
3973
|
+
ranges.push({
|
|
3974
|
+
fromMs: coverageRow.fromMs,
|
|
3975
|
+
toMs: coverageRow.toMs
|
|
3976
|
+
});
|
|
3977
|
+
liquidationCoverageRangesBySymbol.set(symbol, ranges);
|
|
3978
|
+
}
|
|
3979
|
+
}
|
|
3871
3980
|
if (mode === "backtest") {
|
|
3872
3981
|
const rowsCountBySymbol = /* @__PURE__ */ new Map();
|
|
3873
3982
|
for (const row of rows) {
|
|
@@ -6800,7 +6909,9 @@ var import_constants5 = require("@tradejs/core/constants");
|
|
|
6800
6909
|
var import_time5 = require("@tradejs/core/time");
|
|
6801
6910
|
var import_redis4 = require("@tradejs/infra/redis");
|
|
6802
6911
|
var CLOSED_PNL_LIMIT = 100;
|
|
6912
|
+
var CLOSED_PNL_RECONCILIATION_LOOKBACK_MS = 24 * 60 * 60 * 1e3;
|
|
6803
6913
|
var EXCHANGE_HISTORY_MAX_RANGE_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
6914
|
+
var isRuntimeTradeSyncFallbackClose = (trade) => trade.status === "closed" && trade.exitTimestamp === trade.lastSyncedAt && trade.exitPrice == null && trade.actualExitPrice == null && trade.closeFee == null && trade.fundingFee == null;
|
|
6804
6915
|
var splitExchangeHistoryTimeRange = ({
|
|
6805
6916
|
startTime,
|
|
6806
6917
|
endTime,
|
|
@@ -6929,7 +7040,7 @@ var syncRuntimeTrades = async ({
|
|
|
6929
7040
|
);
|
|
6930
7041
|
const closedPnlRows = await loadClosedPnlRows({
|
|
6931
7042
|
connector,
|
|
6932
|
-
startTime,
|
|
7043
|
+
startTime: Math.max(0, startTime - CLOSED_PNL_RECONCILIATION_LOOKBACK_MS),
|
|
6933
7044
|
endTime,
|
|
6934
7045
|
callbacks: closedPnlCallbacks
|
|
6935
7046
|
});
|
|
@@ -6941,14 +7052,14 @@ var syncRuntimeTrades = async ({
|
|
|
6941
7052
|
}
|
|
6942
7053
|
const syncedTrades = [];
|
|
6943
7054
|
for (const trade of trades) {
|
|
6944
|
-
if (trade.status !== "active") {
|
|
7055
|
+
if (trade.status !== "active" && !isRuntimeTradeSyncFallbackClose(trade)) {
|
|
6945
7056
|
syncedTrades.push(trade);
|
|
6946
7057
|
continue;
|
|
6947
7058
|
}
|
|
6948
7059
|
const openPosition = openPositionsBySymbol.get(trade.symbol);
|
|
6949
7060
|
const activeOrderId = activeOrderIdBySymbol.get(trade.symbol);
|
|
6950
7061
|
const isCurrentActiveTrade = activeOrderId === trade.orderId;
|
|
6951
|
-
if (!openPositionsReliable) {
|
|
7062
|
+
if (trade.status === "active" && !openPositionsReliable) {
|
|
6952
7063
|
syncedTrades.push({
|
|
6953
7064
|
...trade,
|
|
6954
7065
|
status: "active",
|
|
@@ -6956,7 +7067,7 @@ var syncRuntimeTrades = async ({
|
|
|
6956
7067
|
});
|
|
6957
7068
|
continue;
|
|
6958
7069
|
}
|
|
6959
|
-
if (isCurrentActiveTrade && openPosition && openPosition.direction === trade.direction) {
|
|
7070
|
+
if (trade.status === "active" && isCurrentActiveTrade && openPosition && openPosition.direction === trade.direction) {
|
|
6960
7071
|
const nextTrade2 = {
|
|
6961
7072
|
...trade,
|
|
6962
7073
|
status: "active",
|
|
@@ -6984,21 +7095,24 @@ var syncRuntimeTrades = async ({
|
|
|
6984
7095
|
continue;
|
|
6985
7096
|
}
|
|
6986
7097
|
const matchedClosedPnl = consumeClosedPnlMatch(closedPnlBuckets, trade);
|
|
7098
|
+
if (!matchedClosedPnl) {
|
|
7099
|
+
continue;
|
|
7100
|
+
}
|
|
6987
7101
|
const nextTrade = {
|
|
6988
7102
|
...trade,
|
|
6989
7103
|
status: "closed",
|
|
6990
|
-
currentPrice: matchedClosedPnl
|
|
6991
|
-
currentPnl: matchedClosedPnl
|
|
6992
|
-
closedPnl: matchedClosedPnl
|
|
6993
|
-
actualEntryPrice: matchedClosedPnl
|
|
6994
|
-
exitPrice: matchedClosedPnl
|
|
6995
|
-
actualExitPrice: matchedClosedPnl
|
|
6996
|
-
exitTimestamp: matchedClosedPnl
|
|
7104
|
+
currentPrice: matchedClosedPnl.exitPrice ?? trade.currentPrice ?? null,
|
|
7105
|
+
currentPnl: matchedClosedPnl.closedPnl,
|
|
7106
|
+
closedPnl: matchedClosedPnl.closedPnl,
|
|
7107
|
+
actualEntryPrice: matchedClosedPnl.entryPrice ?? trade.actualEntryPrice ?? null,
|
|
7108
|
+
exitPrice: matchedClosedPnl.exitPrice ?? trade.exitPrice ?? null,
|
|
7109
|
+
actualExitPrice: matchedClosedPnl.exitPrice ?? trade.actualExitPrice ?? null,
|
|
7110
|
+
exitTimestamp: matchedClosedPnl.closedAt,
|
|
6997
7111
|
exitType: trade.exitType ?? null,
|
|
6998
|
-
openFee: matchedClosedPnl
|
|
6999
|
-
closeFee: matchedClosedPnl
|
|
7000
|
-
fundingFee: matchedClosedPnl
|
|
7001
|
-
totalFee: matchedClosedPnl
|
|
7112
|
+
openFee: matchedClosedPnl.openFee ?? trade.openFee ?? null,
|
|
7113
|
+
closeFee: matchedClosedPnl.closeFee ?? trade.closeFee ?? null,
|
|
7114
|
+
fundingFee: matchedClosedPnl.fundingFee ?? trade.fundingFee ?? null,
|
|
7115
|
+
totalFee: matchedClosedPnl.totalFee ?? trade.totalFee ?? null,
|
|
7002
7116
|
lastSyncedAt: endTime
|
|
7003
7117
|
};
|
|
7004
7118
|
await Promise.all([
|