@tradejs/node 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/backtest.js +138 -16
- package/dist/backtest.mjs +119 -6
- package/dist/{chunk-2XFDY6AT.mjs → chunk-2DZCHRP6.mjs} +22 -12
- package/dist/cli.js +12 -2
- package/dist/cli.mjs +12 -2
- package/dist/strategies.d.mts +2 -1
- package/dist/strategies.d.ts +2 -1
- package/dist/strategies.js +139 -29
- package/dist/strategies.mjs +118 -17
- package/package.json +4 -4
package/dist/backtest.js
CHANGED
|
@@ -1838,11 +1838,12 @@ var enrichSignalWithCoinMarketCapContext = async (params) => {
|
|
|
1838
1838
|
|
|
1839
1839
|
// src/strategyHelpers/derivativesContext.ts
|
|
1840
1840
|
var import_indicators2 = require("@tradejs/core/indicators");
|
|
1841
|
+
var import_data = require("@tradejs/core/data");
|
|
1841
1842
|
var import_strategies3 = require("@tradejs/core/strategies");
|
|
1842
1843
|
var import_constants = require("@tradejs/core/constants");
|
|
1843
1844
|
var import_timescale3 = require("@tradejs/infra/timescale");
|
|
1844
1845
|
var import_logger5 = require("@tradejs/infra/logger");
|
|
1845
|
-
var
|
|
1846
|
+
var STORED_INTERVALS = ["15m", "1h"];
|
|
1846
1847
|
var CONTEXT_INTERVALS = ["15m", "1h"];
|
|
1847
1848
|
var DEFAULT_LOOKBACK_HOURS = 48;
|
|
1848
1849
|
var PRIMARY_DERIVATIVES_REFERENCE_SYMBOL = import_constants.DERIVATIVES_CONTEXT_BASE_REFERENCE_SYMBOLS[0];
|
|
@@ -1868,9 +1869,12 @@ var parseLookbackMs = () => {
|
|
|
1868
1869
|
const normalizedHours = Number.isFinite(hours) && hours > 0 ? hours : DEFAULT_LOOKBACK_HOURS;
|
|
1869
1870
|
return normalizedHours * 60 * 60 * 1e3;
|
|
1870
1871
|
};
|
|
1871
|
-
var
|
|
1872
|
+
var withHourlyFallbackRows = (rowsByInterval) => ({
|
|
1872
1873
|
"15m": rowsByInterval["15m"] ?? [],
|
|
1873
|
-
"1h": (0, import_indicators2.
|
|
1874
|
+
"1h": (0, import_indicators2.buildCoinalyzeHourlyRowsWithFallback)({
|
|
1875
|
+
rows15m: rowsByInterval["15m"],
|
|
1876
|
+
fallbackRows1h: rowsByInterval["1h"]
|
|
1877
|
+
})
|
|
1874
1878
|
});
|
|
1875
1879
|
var getDerivativesContextReferenceSymbols = () => [
|
|
1876
1880
|
...(0, import_constants.resolveDerivativesContextReferenceSymbols)(
|
|
@@ -1994,12 +1998,17 @@ var enrichSignalWithDerivativesContext = async (params) => {
|
|
|
1994
1998
|
const referenceSymbols = getDerivativesContextReferenceSymbols();
|
|
1995
1999
|
const targetSymbol = normalizeSymbol(signal.symbol);
|
|
1996
2000
|
const lookbackMs = parseLookbackMs();
|
|
2001
|
+
const decisionTimeMs = signal.timestamp + (0, import_data.intervalToMs)(signal.interval);
|
|
2002
|
+
const derivativesEndMs = (0, import_indicators2.getLastClosedDerivativesBarStartMs)(
|
|
2003
|
+
decisionTimeMs,
|
|
2004
|
+
"15m"
|
|
2005
|
+
);
|
|
1997
2006
|
const contexts = await Promise.all(
|
|
1998
2007
|
referenceSymbols.map(async (symbol) => {
|
|
1999
2008
|
const rowsByInterval = await (0, import_timescale3.getDerivativesWindow)({
|
|
2000
2009
|
symbol,
|
|
2001
|
-
intervals:
|
|
2002
|
-
endMs:
|
|
2010
|
+
intervals: STORED_INTERVALS,
|
|
2011
|
+
endMs: derivativesEndMs,
|
|
2003
2012
|
lookbackMs
|
|
2004
2013
|
});
|
|
2005
2014
|
return [
|
|
@@ -2007,8 +2016,8 @@ var enrichSignalWithDerivativesContext = async (params) => {
|
|
|
2007
2016
|
(0, import_indicators2.buildDerivativesContext)({
|
|
2008
2017
|
symbol,
|
|
2009
2018
|
direction: signal.direction,
|
|
2010
|
-
timestamp:
|
|
2011
|
-
rowsByInterval:
|
|
2019
|
+
timestamp: derivativesEndMs,
|
|
2020
|
+
rowsByInterval: withHourlyFallbackRows(rowsByInterval),
|
|
2012
2021
|
priceChangePct1h: getSignalPriceChangePct1h(signal),
|
|
2013
2022
|
intervals: CONTEXT_INTERVALS
|
|
2014
2023
|
})
|
|
@@ -2026,15 +2035,15 @@ var enrichSignalWithDerivativesContext = async (params) => {
|
|
|
2026
2035
|
const fetchedTargetContext = shouldFetchTargetContext ? await (async () => {
|
|
2027
2036
|
const rowsByInterval = await (0, import_timescale3.getDerivativesWindow)({
|
|
2028
2037
|
symbol: targetSymbol,
|
|
2029
|
-
intervals:
|
|
2030
|
-
endMs:
|
|
2038
|
+
intervals: STORED_INTERVALS,
|
|
2039
|
+
endMs: derivativesEndMs,
|
|
2031
2040
|
lookbackMs
|
|
2032
2041
|
});
|
|
2033
2042
|
const context = (0, import_indicators2.buildDerivativesContext)({
|
|
2034
2043
|
symbol: targetSymbol,
|
|
2035
2044
|
direction: signal.direction,
|
|
2036
|
-
timestamp:
|
|
2037
|
-
rowsByInterval:
|
|
2045
|
+
timestamp: derivativesEndMs,
|
|
2046
|
+
rowsByInterval: withHourlyFallbackRows(rowsByInterval),
|
|
2038
2047
|
priceChangePct1h: getSignalPriceChangePct1h(signal),
|
|
2039
2048
|
intervals: CONTEXT_INTERVALS
|
|
2040
2049
|
});
|
|
@@ -2886,7 +2895,10 @@ var createTestConnector = (connector, context) => {
|
|
|
2886
2895
|
}
|
|
2887
2896
|
},
|
|
2888
2897
|
placeOrder: async (order) => {
|
|
2889
|
-
|
|
2898
|
+
const isPositionIncrease = Boolean(
|
|
2899
|
+
currentPosition && order.positionIntent === "increase" && currentPosition.direction === order.direction
|
|
2900
|
+
);
|
|
2901
|
+
if (currentPosition && !isPositionIncrease) {
|
|
2890
2902
|
return false;
|
|
2891
2903
|
}
|
|
2892
2904
|
const isLong = order.direction === "LONG";
|
|
@@ -2900,9 +2912,114 @@ var createTestConnector = (connector, context) => {
|
|
|
2900
2912
|
stage: "entry",
|
|
2901
2913
|
signal: order.signal
|
|
2902
2914
|
});
|
|
2903
|
-
|
|
2915
|
+
const previousPosition = currentPosition;
|
|
2916
|
+
const previousQty = previousPosition?.qty ?? 0;
|
|
2917
|
+
const resultingQty = previousQty + order.qty;
|
|
2918
|
+
const resultingEntryPrice = previousPosition ? getWeightedAverage(
|
|
2919
|
+
previousPosition.price,
|
|
2920
|
+
previousQty,
|
|
2921
|
+
entryPrice,
|
|
2922
|
+
order.qty
|
|
2923
|
+
) : entryPrice;
|
|
2924
|
+
currentPosition = previousPosition ? {
|
|
2925
|
+
...previousPosition,
|
|
2926
|
+
qty: resultingQty,
|
|
2927
|
+
price: resultingEntryPrice
|
|
2928
|
+
} : { ...order, price: entryPrice, amount };
|
|
2929
|
+
originalQty = resultingQty;
|
|
2930
|
+
if (isPositionIncrease) {
|
|
2931
|
+
const { fee: fee2, profit: profit2 } = getNetProfit({
|
|
2932
|
+
grossProfit: 0,
|
|
2933
|
+
price: entryPrice,
|
|
2934
|
+
qty: order.qty,
|
|
2935
|
+
feeRate: order.isLimit ? makerFeeRate : takerFeeRate
|
|
2936
|
+
});
|
|
2937
|
+
const entrySlippageCost2 = getSlippageCost({
|
|
2938
|
+
requestedPrice: order.price,
|
|
2939
|
+
executionPrice: entryPrice,
|
|
2940
|
+
direction: order.direction,
|
|
2941
|
+
stage: "entry",
|
|
2942
|
+
qty: order.qty
|
|
2943
|
+
});
|
|
2944
|
+
amount += profit2;
|
|
2945
|
+
currentPositionProfit += profit2;
|
|
2946
|
+
if (currentTradeResult) {
|
|
2947
|
+
const requestedEntryPrice = getWeightedAverage(
|
|
2948
|
+
currentTradeResult.requestedEntryPrice,
|
|
2949
|
+
currentTradeResult.qty,
|
|
2950
|
+
order.price,
|
|
2951
|
+
order.qty
|
|
2952
|
+
);
|
|
2953
|
+
const weightedEntryPrice = getWeightedAverage(
|
|
2954
|
+
currentTradeResult.entryPrice,
|
|
2955
|
+
currentTradeResult.qty,
|
|
2956
|
+
entryPrice,
|
|
2957
|
+
order.qty
|
|
2958
|
+
);
|
|
2959
|
+
const entryBaseSlippageBps = getWeightedAverage(
|
|
2960
|
+
currentTradeResult.entryBaseSlippageBps,
|
|
2961
|
+
currentTradeResult.qty,
|
|
2962
|
+
entrySlippageBreakdown.baseSlippageBps,
|
|
2963
|
+
order.qty
|
|
2964
|
+
);
|
|
2965
|
+
const entrySpreadBps = getWeightedAverage(
|
|
2966
|
+
currentTradeResult.entrySpreadBps,
|
|
2967
|
+
currentTradeResult.qty,
|
|
2968
|
+
entrySlippageBreakdown.spreadBps,
|
|
2969
|
+
order.qty
|
|
2970
|
+
);
|
|
2971
|
+
const entrySpreadSlippageBps = getWeightedAverage(
|
|
2972
|
+
currentTradeResult.entrySpreadSlippageBps,
|
|
2973
|
+
currentTradeResult.qty,
|
|
2974
|
+
entrySlippageBreakdown.spreadSlippageBps,
|
|
2975
|
+
order.qty
|
|
2976
|
+
);
|
|
2977
|
+
const entryMarketImpactBps = getWeightedAverage(
|
|
2978
|
+
currentTradeResult.entryMarketImpactBps,
|
|
2979
|
+
currentTradeResult.qty,
|
|
2980
|
+
entrySlippageBreakdown.marketImpactBps,
|
|
2981
|
+
order.qty
|
|
2982
|
+
);
|
|
2983
|
+
const entryDelayRiskBps = getWeightedAverage(
|
|
2984
|
+
currentTradeResult.entryDelayRiskBps,
|
|
2985
|
+
currentTradeResult.qty,
|
|
2986
|
+
entrySlippageBreakdown.delayRiskBps,
|
|
2987
|
+
order.qty
|
|
2988
|
+
);
|
|
2989
|
+
const totalEntrySlippageCost = currentTradeResult.entrySlippageCost + entrySlippageCost2;
|
|
2990
|
+
currentTradeResult = {
|
|
2991
|
+
...currentTradeResult,
|
|
2992
|
+
qty: currentTradeResult.qty + order.qty,
|
|
2993
|
+
requestedEntryPrice,
|
|
2994
|
+
entryPrice: weightedEntryPrice,
|
|
2995
|
+
netProfit: currentTradeResult.netProfit + profit2,
|
|
2996
|
+
openFee: currentTradeResult.openFee + fee2,
|
|
2997
|
+
totalFee: currentTradeResult.totalFee + fee2,
|
|
2998
|
+
entrySlippagePrice: weightedEntryPrice - requestedEntryPrice,
|
|
2999
|
+
entrySlippageBps: getSlippageBps(
|
|
3000
|
+
requestedEntryPrice,
|
|
3001
|
+
weightedEntryPrice
|
|
3002
|
+
),
|
|
3003
|
+
entryBaseSlippageBps,
|
|
3004
|
+
entrySpreadBps,
|
|
3005
|
+
entrySpreadSlippageBps,
|
|
3006
|
+
entryMarketImpactBps,
|
|
3007
|
+
entryDelayRiskBps,
|
|
3008
|
+
entrySlippageCost: totalEntrySlippageCost,
|
|
3009
|
+
totalSlippageCost: totalEntrySlippageCost + currentTradeResult.exitSlippageCost
|
|
3010
|
+
};
|
|
3011
|
+
}
|
|
3012
|
+
logOrder({
|
|
3013
|
+
...order,
|
|
3014
|
+
price: entryPrice,
|
|
3015
|
+
profit: profit2,
|
|
3016
|
+
fee: fee2,
|
|
3017
|
+
type: isLong ? "OPEN_LONG" : "OPEN_SHORT",
|
|
3018
|
+
...getExecutionSlippageLogData(entrySlippageBreakdown, "entry")
|
|
3019
|
+
});
|
|
3020
|
+
return true;
|
|
3021
|
+
}
|
|
2904
3022
|
currentSignalId = typeof order.signal?.signalId === "string" && order.signal.signalId ? order.signal.signalId : null;
|
|
2905
|
-
originalQty = order.qty;
|
|
2906
3023
|
const { fee, profit } = getNetProfit({
|
|
2907
3024
|
grossProfit: 0,
|
|
2908
3025
|
price: entryPrice,
|
|
@@ -2969,16 +3086,21 @@ var createTestConnector = (connector, context) => {
|
|
|
2969
3086
|
return false;
|
|
2970
3087
|
}
|
|
2971
3088
|
takeProfits = Array.isArray(nextTakeProfits) ? nextTakeProfits.map((tp) => ({ ...tp })) : [];
|
|
3089
|
+
const fullTakeProfit = takeProfits.length === 1 && takeProfits[0]?.rate === 1 ? takeProfits[0].price : void 0;
|
|
3090
|
+
currentPosition = {
|
|
3091
|
+
...currentPosition,
|
|
3092
|
+
tpPrice: fullTakeProfit
|
|
3093
|
+
};
|
|
2972
3094
|
return true;
|
|
2973
3095
|
},
|
|
2974
3096
|
setStopLoss: async ({ stopLossPrice: nextStopLossPrice }) => {
|
|
2975
3097
|
if (!currentPosition) {
|
|
2976
3098
|
return false;
|
|
2977
3099
|
}
|
|
2978
|
-
stopLossPrice = nextStopLossPrice
|
|
3100
|
+
stopLossPrice = nextStopLossPrice ?? null;
|
|
2979
3101
|
currentPosition = {
|
|
2980
3102
|
...currentPosition,
|
|
2981
|
-
|
|
3103
|
+
slPrice: stopLossPrice ?? void 0
|
|
2982
3104
|
};
|
|
2983
3105
|
return true;
|
|
2984
3106
|
},
|
package/dist/backtest.mjs
CHANGED
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
enrichSignalWithBinanceMarketContext,
|
|
8
8
|
enrichSignalWithCoinMarketCapContext,
|
|
9
9
|
enrichSignalWithDerivativesContext
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-2DZCHRP6.mjs";
|
|
11
11
|
import {
|
|
12
12
|
buildAiPayload
|
|
13
13
|
} from "./chunk-IUZML4RK.mjs";
|
|
@@ -625,7 +625,10 @@ var createTestConnector = (connector, context) => {
|
|
|
625
625
|
}
|
|
626
626
|
},
|
|
627
627
|
placeOrder: async (order) => {
|
|
628
|
-
|
|
628
|
+
const isPositionIncrease = Boolean(
|
|
629
|
+
currentPosition && order.positionIntent === "increase" && currentPosition.direction === order.direction
|
|
630
|
+
);
|
|
631
|
+
if (currentPosition && !isPositionIncrease) {
|
|
629
632
|
return false;
|
|
630
633
|
}
|
|
631
634
|
const isLong = order.direction === "LONG";
|
|
@@ -639,9 +642,114 @@ var createTestConnector = (connector, context) => {
|
|
|
639
642
|
stage: "entry",
|
|
640
643
|
signal: order.signal
|
|
641
644
|
});
|
|
642
|
-
|
|
645
|
+
const previousPosition = currentPosition;
|
|
646
|
+
const previousQty = previousPosition?.qty ?? 0;
|
|
647
|
+
const resultingQty = previousQty + order.qty;
|
|
648
|
+
const resultingEntryPrice = previousPosition ? getWeightedAverage(
|
|
649
|
+
previousPosition.price,
|
|
650
|
+
previousQty,
|
|
651
|
+
entryPrice,
|
|
652
|
+
order.qty
|
|
653
|
+
) : entryPrice;
|
|
654
|
+
currentPosition = previousPosition ? {
|
|
655
|
+
...previousPosition,
|
|
656
|
+
qty: resultingQty,
|
|
657
|
+
price: resultingEntryPrice
|
|
658
|
+
} : { ...order, price: entryPrice, amount };
|
|
659
|
+
originalQty = resultingQty;
|
|
660
|
+
if (isPositionIncrease) {
|
|
661
|
+
const { fee: fee2, profit: profit2 } = getNetProfit({
|
|
662
|
+
grossProfit: 0,
|
|
663
|
+
price: entryPrice,
|
|
664
|
+
qty: order.qty,
|
|
665
|
+
feeRate: order.isLimit ? makerFeeRate : takerFeeRate
|
|
666
|
+
});
|
|
667
|
+
const entrySlippageCost2 = getSlippageCost({
|
|
668
|
+
requestedPrice: order.price,
|
|
669
|
+
executionPrice: entryPrice,
|
|
670
|
+
direction: order.direction,
|
|
671
|
+
stage: "entry",
|
|
672
|
+
qty: order.qty
|
|
673
|
+
});
|
|
674
|
+
amount += profit2;
|
|
675
|
+
currentPositionProfit += profit2;
|
|
676
|
+
if (currentTradeResult) {
|
|
677
|
+
const requestedEntryPrice = getWeightedAverage(
|
|
678
|
+
currentTradeResult.requestedEntryPrice,
|
|
679
|
+
currentTradeResult.qty,
|
|
680
|
+
order.price,
|
|
681
|
+
order.qty
|
|
682
|
+
);
|
|
683
|
+
const weightedEntryPrice = getWeightedAverage(
|
|
684
|
+
currentTradeResult.entryPrice,
|
|
685
|
+
currentTradeResult.qty,
|
|
686
|
+
entryPrice,
|
|
687
|
+
order.qty
|
|
688
|
+
);
|
|
689
|
+
const entryBaseSlippageBps = getWeightedAverage(
|
|
690
|
+
currentTradeResult.entryBaseSlippageBps,
|
|
691
|
+
currentTradeResult.qty,
|
|
692
|
+
entrySlippageBreakdown.baseSlippageBps,
|
|
693
|
+
order.qty
|
|
694
|
+
);
|
|
695
|
+
const entrySpreadBps = getWeightedAverage(
|
|
696
|
+
currentTradeResult.entrySpreadBps,
|
|
697
|
+
currentTradeResult.qty,
|
|
698
|
+
entrySlippageBreakdown.spreadBps,
|
|
699
|
+
order.qty
|
|
700
|
+
);
|
|
701
|
+
const entrySpreadSlippageBps = getWeightedAverage(
|
|
702
|
+
currentTradeResult.entrySpreadSlippageBps,
|
|
703
|
+
currentTradeResult.qty,
|
|
704
|
+
entrySlippageBreakdown.spreadSlippageBps,
|
|
705
|
+
order.qty
|
|
706
|
+
);
|
|
707
|
+
const entryMarketImpactBps = getWeightedAverage(
|
|
708
|
+
currentTradeResult.entryMarketImpactBps,
|
|
709
|
+
currentTradeResult.qty,
|
|
710
|
+
entrySlippageBreakdown.marketImpactBps,
|
|
711
|
+
order.qty
|
|
712
|
+
);
|
|
713
|
+
const entryDelayRiskBps = getWeightedAverage(
|
|
714
|
+
currentTradeResult.entryDelayRiskBps,
|
|
715
|
+
currentTradeResult.qty,
|
|
716
|
+
entrySlippageBreakdown.delayRiskBps,
|
|
717
|
+
order.qty
|
|
718
|
+
);
|
|
719
|
+
const totalEntrySlippageCost = currentTradeResult.entrySlippageCost + entrySlippageCost2;
|
|
720
|
+
currentTradeResult = {
|
|
721
|
+
...currentTradeResult,
|
|
722
|
+
qty: currentTradeResult.qty + order.qty,
|
|
723
|
+
requestedEntryPrice,
|
|
724
|
+
entryPrice: weightedEntryPrice,
|
|
725
|
+
netProfit: currentTradeResult.netProfit + profit2,
|
|
726
|
+
openFee: currentTradeResult.openFee + fee2,
|
|
727
|
+
totalFee: currentTradeResult.totalFee + fee2,
|
|
728
|
+
entrySlippagePrice: weightedEntryPrice - requestedEntryPrice,
|
|
729
|
+
entrySlippageBps: getSlippageBps(
|
|
730
|
+
requestedEntryPrice,
|
|
731
|
+
weightedEntryPrice
|
|
732
|
+
),
|
|
733
|
+
entryBaseSlippageBps,
|
|
734
|
+
entrySpreadBps,
|
|
735
|
+
entrySpreadSlippageBps,
|
|
736
|
+
entryMarketImpactBps,
|
|
737
|
+
entryDelayRiskBps,
|
|
738
|
+
entrySlippageCost: totalEntrySlippageCost,
|
|
739
|
+
totalSlippageCost: totalEntrySlippageCost + currentTradeResult.exitSlippageCost
|
|
740
|
+
};
|
|
741
|
+
}
|
|
742
|
+
logOrder({
|
|
743
|
+
...order,
|
|
744
|
+
price: entryPrice,
|
|
745
|
+
profit: profit2,
|
|
746
|
+
fee: fee2,
|
|
747
|
+
type: isLong ? "OPEN_LONG" : "OPEN_SHORT",
|
|
748
|
+
...getExecutionSlippageLogData(entrySlippageBreakdown, "entry")
|
|
749
|
+
});
|
|
750
|
+
return true;
|
|
751
|
+
}
|
|
643
752
|
currentSignalId = typeof order.signal?.signalId === "string" && order.signal.signalId ? order.signal.signalId : null;
|
|
644
|
-
originalQty = order.qty;
|
|
645
753
|
const { fee, profit } = getNetProfit({
|
|
646
754
|
grossProfit: 0,
|
|
647
755
|
price: entryPrice,
|
|
@@ -708,16 +816,21 @@ var createTestConnector = (connector, context) => {
|
|
|
708
816
|
return false;
|
|
709
817
|
}
|
|
710
818
|
takeProfits = Array.isArray(nextTakeProfits) ? nextTakeProfits.map((tp) => ({ ...tp })) : [];
|
|
819
|
+
const fullTakeProfit = takeProfits.length === 1 && takeProfits[0]?.rate === 1 ? takeProfits[0].price : void 0;
|
|
820
|
+
currentPosition = {
|
|
821
|
+
...currentPosition,
|
|
822
|
+
tpPrice: fullTakeProfit
|
|
823
|
+
};
|
|
711
824
|
return true;
|
|
712
825
|
},
|
|
713
826
|
setStopLoss: async ({ stopLossPrice: nextStopLossPrice }) => {
|
|
714
827
|
if (!currentPosition) {
|
|
715
828
|
return false;
|
|
716
829
|
}
|
|
717
|
-
stopLossPrice = nextStopLossPrice
|
|
830
|
+
stopLossPrice = nextStopLossPrice ?? null;
|
|
718
831
|
currentPosition = {
|
|
719
832
|
...currentPosition,
|
|
720
|
-
|
|
833
|
+
slPrice: stopLossPrice ?? void 0
|
|
721
834
|
};
|
|
722
835
|
return true;
|
|
723
836
|
},
|
|
@@ -747,8 +747,10 @@ var enrichSignalWithCoinMarketCapContext = async (params) => {
|
|
|
747
747
|
// src/strategyHelpers/derivativesContext.ts
|
|
748
748
|
import {
|
|
749
749
|
buildDerivativesContext,
|
|
750
|
-
|
|
750
|
+
buildCoinalyzeHourlyRowsWithFallback,
|
|
751
|
+
getLastClosedDerivativesBarStartMs
|
|
751
752
|
} from "@tradejs/core/indicators";
|
|
753
|
+
import { intervalToMs } from "@tradejs/core/data";
|
|
752
754
|
import { refreshSignalBaseContextGateFeatures as refreshSignalBaseContextGateFeatures3 } from "@tradejs/core/strategies";
|
|
753
755
|
import {
|
|
754
756
|
DERIVATIVES_CONTEXT_BASE_REFERENCE_SYMBOLS,
|
|
@@ -756,7 +758,7 @@ import {
|
|
|
756
758
|
} from "@tradejs/core/constants";
|
|
757
759
|
import { getDerivativesWindow } from "@tradejs/infra/timescale";
|
|
758
760
|
import { logger as logger3 } from "@tradejs/infra/logger";
|
|
759
|
-
var
|
|
761
|
+
var STORED_INTERVALS = ["15m", "1h"];
|
|
760
762
|
var CONTEXT_INTERVALS = ["15m", "1h"];
|
|
761
763
|
var DEFAULT_LOOKBACK_HOURS = 48;
|
|
762
764
|
var PRIMARY_DERIVATIVES_REFERENCE_SYMBOL = DERIVATIVES_CONTEXT_BASE_REFERENCE_SYMBOLS[0];
|
|
@@ -782,9 +784,12 @@ var parseLookbackMs = () => {
|
|
|
782
784
|
const normalizedHours = Number.isFinite(hours) && hours > 0 ? hours : DEFAULT_LOOKBACK_HOURS;
|
|
783
785
|
return normalizedHours * 60 * 60 * 1e3;
|
|
784
786
|
};
|
|
785
|
-
var
|
|
787
|
+
var withHourlyFallbackRows = (rowsByInterval) => ({
|
|
786
788
|
"15m": rowsByInterval["15m"] ?? [],
|
|
787
|
-
"1h":
|
|
789
|
+
"1h": buildCoinalyzeHourlyRowsWithFallback({
|
|
790
|
+
rows15m: rowsByInterval["15m"],
|
|
791
|
+
fallbackRows1h: rowsByInterval["1h"]
|
|
792
|
+
})
|
|
788
793
|
});
|
|
789
794
|
var getDerivativesContextReferenceSymbols = () => [
|
|
790
795
|
...resolveDerivativesContextReferenceSymbols(
|
|
@@ -908,12 +913,17 @@ var enrichSignalWithDerivativesContext = async (params) => {
|
|
|
908
913
|
const referenceSymbols = getDerivativesContextReferenceSymbols();
|
|
909
914
|
const targetSymbol = normalizeSymbol(signal.symbol);
|
|
910
915
|
const lookbackMs = parseLookbackMs();
|
|
916
|
+
const decisionTimeMs = signal.timestamp + intervalToMs(signal.interval);
|
|
917
|
+
const derivativesEndMs = getLastClosedDerivativesBarStartMs(
|
|
918
|
+
decisionTimeMs,
|
|
919
|
+
"15m"
|
|
920
|
+
);
|
|
911
921
|
const contexts = await Promise.all(
|
|
912
922
|
referenceSymbols.map(async (symbol) => {
|
|
913
923
|
const rowsByInterval = await getDerivativesWindow({
|
|
914
924
|
symbol,
|
|
915
|
-
intervals:
|
|
916
|
-
endMs:
|
|
925
|
+
intervals: STORED_INTERVALS,
|
|
926
|
+
endMs: derivativesEndMs,
|
|
917
927
|
lookbackMs
|
|
918
928
|
});
|
|
919
929
|
return [
|
|
@@ -921,8 +931,8 @@ var enrichSignalWithDerivativesContext = async (params) => {
|
|
|
921
931
|
buildDerivativesContext({
|
|
922
932
|
symbol,
|
|
923
933
|
direction: signal.direction,
|
|
924
|
-
timestamp:
|
|
925
|
-
rowsByInterval:
|
|
934
|
+
timestamp: derivativesEndMs,
|
|
935
|
+
rowsByInterval: withHourlyFallbackRows(rowsByInterval),
|
|
926
936
|
priceChangePct1h: getSignalPriceChangePct1h(signal),
|
|
927
937
|
intervals: CONTEXT_INTERVALS
|
|
928
938
|
})
|
|
@@ -940,15 +950,15 @@ var enrichSignalWithDerivativesContext = async (params) => {
|
|
|
940
950
|
const fetchedTargetContext = shouldFetchTargetContext ? await (async () => {
|
|
941
951
|
const rowsByInterval = await getDerivativesWindow({
|
|
942
952
|
symbol: targetSymbol,
|
|
943
|
-
intervals:
|
|
944
|
-
endMs:
|
|
953
|
+
intervals: STORED_INTERVALS,
|
|
954
|
+
endMs: derivativesEndMs,
|
|
945
955
|
lookbackMs
|
|
946
956
|
});
|
|
947
957
|
const context = buildDerivativesContext({
|
|
948
958
|
symbol: targetSymbol,
|
|
949
959
|
direction: signal.direction,
|
|
950
|
-
timestamp:
|
|
951
|
-
rowsByInterval:
|
|
960
|
+
timestamp: derivativesEndMs,
|
|
961
|
+
rowsByInterval: withHourlyFallbackRows(rowsByInterval),
|
|
952
962
|
priceChangePct1h: getSignalPriceChangePct1h(signal),
|
|
953
963
|
intervals: CONTEXT_INTERVALS
|
|
954
964
|
});
|
package/dist/cli.js
CHANGED
|
@@ -7071,7 +7071,8 @@ var SCREENSHOT_NAVIGATION_RETRY_DELAY_MS = 2e3;
|
|
|
7071
7071
|
var SCREENSHOT_CAPTURE_ATTEMPTS = 2;
|
|
7072
7072
|
var SCREENSHOT_CAPTURE_RETRY_DELAY_MS = 2e3;
|
|
7073
7073
|
var SCREENSHOT_NAVIGATION_TIMEOUT_MS = 3e4;
|
|
7074
|
-
var
|
|
7074
|
+
var SCREENSHOT_READY_TIMEOUT_MS = 3e4;
|
|
7075
|
+
var SCREENSHOT_READY_SELECTOR = '[data-screenshot-ready="true"]';
|
|
7075
7076
|
var SCREENSHOT_CONSOLE_LOG_LIMIT = 20;
|
|
7076
7077
|
var SCREENSHOT_CONSOLE_TEXT_LIMIT = 500;
|
|
7077
7078
|
var SCREENSHOT_BROWSER_STDERR = process.env.SCREENSHOT_BROWSER_STDERR === "1";
|
|
@@ -7400,7 +7401,16 @@ var screenDashboard = async (signal, projectRoot, userName = "root") => {
|
|
|
7400
7401
|
`Failed to open dashboard ${dashboardUrl}: ${gotoError.message || String(gotoError)}`
|
|
7401
7402
|
);
|
|
7402
7403
|
}
|
|
7403
|
-
await (
|
|
7404
|
+
await page.waitForSelector(SCREENSHOT_READY_SELECTOR, {
|
|
7405
|
+
timeout: SCREENSHOT_READY_TIMEOUT_MS
|
|
7406
|
+
});
|
|
7407
|
+
await page.evaluate(
|
|
7408
|
+
() => new Promise((resolve) => {
|
|
7409
|
+
requestAnimationFrame(
|
|
7410
|
+
() => requestAnimationFrame(() => resolve())
|
|
7411
|
+
);
|
|
7412
|
+
})
|
|
7413
|
+
);
|
|
7404
7414
|
await import_promises.default.mkdir(getScreenshotsDir(projectRoot), { recursive: true });
|
|
7405
7415
|
await page.screenshot({
|
|
7406
7416
|
path: screenshotPath,
|
package/dist/cli.mjs
CHANGED
|
@@ -74,7 +74,8 @@ var SCREENSHOT_NAVIGATION_RETRY_DELAY_MS = 2e3;
|
|
|
74
74
|
var SCREENSHOT_CAPTURE_ATTEMPTS = 2;
|
|
75
75
|
var SCREENSHOT_CAPTURE_RETRY_DELAY_MS = 2e3;
|
|
76
76
|
var SCREENSHOT_NAVIGATION_TIMEOUT_MS = 3e4;
|
|
77
|
-
var
|
|
77
|
+
var SCREENSHOT_READY_TIMEOUT_MS = 3e4;
|
|
78
|
+
var SCREENSHOT_READY_SELECTOR = '[data-screenshot-ready="true"]';
|
|
78
79
|
var SCREENSHOT_CONSOLE_LOG_LIMIT = 20;
|
|
79
80
|
var SCREENSHOT_CONSOLE_TEXT_LIMIT = 500;
|
|
80
81
|
var SCREENSHOT_BROWSER_STDERR = process.env.SCREENSHOT_BROWSER_STDERR === "1";
|
|
@@ -403,7 +404,16 @@ var screenDashboard = async (signal, projectRoot, userName = "root") => {
|
|
|
403
404
|
`Failed to open dashboard ${dashboardUrl}: ${gotoError.message || String(gotoError)}`
|
|
404
405
|
);
|
|
405
406
|
}
|
|
406
|
-
await
|
|
407
|
+
await page.waitForSelector(SCREENSHOT_READY_SELECTOR, {
|
|
408
|
+
timeout: SCREENSHOT_READY_TIMEOUT_MS
|
|
409
|
+
});
|
|
410
|
+
await page.evaluate(
|
|
411
|
+
() => new Promise((resolve) => {
|
|
412
|
+
requestAnimationFrame(
|
|
413
|
+
() => requestAnimationFrame(() => resolve())
|
|
414
|
+
);
|
|
415
|
+
})
|
|
416
|
+
);
|
|
407
417
|
await fs.mkdir(getScreenshotsDir(projectRoot), { recursive: true });
|
|
408
418
|
await page.screenshot({
|
|
409
419
|
path: screenshotPath,
|
package/dist/strategies.d.mts
CHANGED
|
@@ -50,12 +50,13 @@ interface ExecuteEntryOrderParams {
|
|
|
50
50
|
timestamp: number;
|
|
51
51
|
takeProfits: Tp[];
|
|
52
52
|
stopLossPrice: number | null;
|
|
53
|
+
positionIntent?: 'open' | 'increase';
|
|
53
54
|
leverage?: number;
|
|
54
55
|
signal: Signal;
|
|
55
56
|
beforePlaceOrder?: () => Promise<void>;
|
|
56
57
|
recordRuntimeTrade?: boolean;
|
|
57
58
|
}
|
|
58
|
-
declare const executeEntryOrder: ({ connector, userName, symbol, direction, qty, currentPrice, timestamp, takeProfits, stopLossPrice, signal, beforePlaceOrder, recordRuntimeTrade, leverage, }: ExecuteEntryOrderParams) => Promise<number>;
|
|
59
|
+
declare const executeEntryOrder: ({ connector, userName, symbol, direction, qty, currentPrice, timestamp, takeProfits, stopLossPrice, positionIntent, signal, beforePlaceOrder, recordRuntimeTrade, leverage, }: ExecuteEntryOrderParams) => Promise<number>;
|
|
59
60
|
|
|
60
61
|
declare const enrichSignalWithBinanceMarketContext: (params: {
|
|
61
62
|
signal: Signal;
|
package/dist/strategies.d.ts
CHANGED
|
@@ -50,12 +50,13 @@ interface ExecuteEntryOrderParams {
|
|
|
50
50
|
timestamp: number;
|
|
51
51
|
takeProfits: Tp[];
|
|
52
52
|
stopLossPrice: number | null;
|
|
53
|
+
positionIntent?: 'open' | 'increase';
|
|
53
54
|
leverage?: number;
|
|
54
55
|
signal: Signal;
|
|
55
56
|
beforePlaceOrder?: () => Promise<void>;
|
|
56
57
|
recordRuntimeTrade?: boolean;
|
|
57
58
|
}
|
|
58
|
-
declare const executeEntryOrder: ({ connector, userName, symbol, direction, qty, currentPrice, timestamp, takeProfits, stopLossPrice, signal, beforePlaceOrder, recordRuntimeTrade, leverage, }: ExecuteEntryOrderParams) => Promise<number>;
|
|
59
|
+
declare const executeEntryOrder: ({ connector, userName, symbol, direction, qty, currentPrice, timestamp, takeProfits, stopLossPrice, positionIntent, signal, beforePlaceOrder, recordRuntimeTrade, leverage, }: ExecuteEntryOrderParams) => Promise<number>;
|
|
59
60
|
|
|
60
61
|
declare const enrichSignalWithBinanceMarketContext: (params: {
|
|
61
62
|
signal: Signal;
|
package/dist/strategies.js
CHANGED
|
@@ -7196,7 +7196,7 @@ var askAI = async (signal, options = {}) => {
|
|
|
7196
7196
|
// src/strategyRuntime.ts
|
|
7197
7197
|
var import_node_path2 = __toESM(require("path"));
|
|
7198
7198
|
var import_constants4 = require("@tradejs/core/constants");
|
|
7199
|
-
var
|
|
7199
|
+
var import_data2 = require("@tradejs/core/data");
|
|
7200
7200
|
var import_strategies4 = require("@tradejs/core/strategies");
|
|
7201
7201
|
var import_logger8 = require("@tradejs/infra/logger");
|
|
7202
7202
|
|
|
@@ -7285,6 +7285,10 @@ var recordRuntimeTradeOpen = async (params) => {
|
|
|
7285
7285
|
}
|
|
7286
7286
|
const record = {
|
|
7287
7287
|
...params,
|
|
7288
|
+
entryCount: 1,
|
|
7289
|
+
lastEntryPrice: params.entryPrice,
|
|
7290
|
+
lastEntryQty: params.qty,
|
|
7291
|
+
lastEntryTimestamp: params.entryTimestamp,
|
|
7288
7292
|
status: "active",
|
|
7289
7293
|
currentPrice: params.entryPrice,
|
|
7290
7294
|
currentPnl: 0,
|
|
@@ -7321,6 +7325,73 @@ var recordRuntimeTradeOpen = async (params) => {
|
|
|
7321
7325
|
}
|
|
7322
7326
|
return record;
|
|
7323
7327
|
};
|
|
7328
|
+
var recordRuntimeTradeIncrease = async (params) => {
|
|
7329
|
+
const {
|
|
7330
|
+
userName,
|
|
7331
|
+
strategy,
|
|
7332
|
+
symbol,
|
|
7333
|
+
direction,
|
|
7334
|
+
resultingQty,
|
|
7335
|
+
resultingEntryPrice,
|
|
7336
|
+
addedQty,
|
|
7337
|
+
addedEntryPrice,
|
|
7338
|
+
entryTimestamp,
|
|
7339
|
+
fee,
|
|
7340
|
+
accountId,
|
|
7341
|
+
deploymentId
|
|
7342
|
+
} = params;
|
|
7343
|
+
if (!userName) {
|
|
7344
|
+
return null;
|
|
7345
|
+
}
|
|
7346
|
+
const existing = await getActiveRuntimeTrade({
|
|
7347
|
+
userName,
|
|
7348
|
+
symbol,
|
|
7349
|
+
accountId,
|
|
7350
|
+
deploymentId
|
|
7351
|
+
});
|
|
7352
|
+
if (!existing || existing.strategy !== strategy || existing.direction !== direction) {
|
|
7353
|
+
return null;
|
|
7354
|
+
}
|
|
7355
|
+
const addedFee = typeof fee === "number" && Number.isFinite(fee) ? fee : 0;
|
|
7356
|
+
const openFee = (existing.openFee ?? existing.fee ?? 0) + addedFee;
|
|
7357
|
+
const totalFee = (existing.totalFee ?? existing.fee ?? 0) + addedFee;
|
|
7358
|
+
const next = {
|
|
7359
|
+
...existing,
|
|
7360
|
+
qty: resultingQty,
|
|
7361
|
+
entryPrice: resultingEntryPrice,
|
|
7362
|
+
entryCount: Math.max(1, existing.entryCount ?? 1) + 1,
|
|
7363
|
+
lastEntryPrice: addedEntryPrice,
|
|
7364
|
+
lastEntryQty: addedQty,
|
|
7365
|
+
lastEntryTimestamp: entryTimestamp,
|
|
7366
|
+
currentPrice: resultingEntryPrice,
|
|
7367
|
+
currentPnl: 0,
|
|
7368
|
+
fee: openFee,
|
|
7369
|
+
openFee,
|
|
7370
|
+
totalFee,
|
|
7371
|
+
lastSyncedAt: now()
|
|
7372
|
+
};
|
|
7373
|
+
const dayKey = (0, import_time.getRuntimeStorageDayKey)(existing.entryTimestamp);
|
|
7374
|
+
try {
|
|
7375
|
+
await Promise.all([
|
|
7376
|
+
(0, import_redis2.setData)(import_redis2.redisKeys.runtimeTrade(userName, existing.orderId), next, {
|
|
7377
|
+
expire: 0
|
|
7378
|
+
}),
|
|
7379
|
+
(0, import_redis2.setHashJsonField)(
|
|
7380
|
+
import_redis2.redisKeys.runtimeTradeBucket(userName, dayKey),
|
|
7381
|
+
existing.orderId,
|
|
7382
|
+
next,
|
|
7383
|
+
{ expire: 0 }
|
|
7384
|
+
)
|
|
7385
|
+
]);
|
|
7386
|
+
} catch (error) {
|
|
7387
|
+
import_logger3.logger.error(
|
|
7388
|
+
"runtime trade increase journal failed: %s %s",
|
|
7389
|
+
symbol,
|
|
7390
|
+
error?.message || String(error)
|
|
7391
|
+
);
|
|
7392
|
+
}
|
|
7393
|
+
return next;
|
|
7394
|
+
};
|
|
7324
7395
|
var getActiveRuntimeTrade = async (params) => {
|
|
7325
7396
|
const { userName, symbol, accountId, deploymentId } = params;
|
|
7326
7397
|
if (!userName) {
|
|
@@ -7424,11 +7495,12 @@ var markRuntimeTradeClosed = async (params) => {
|
|
|
7424
7495
|
|
|
7425
7496
|
// src/strategyHelpers/derivativesContext.ts
|
|
7426
7497
|
var import_indicators2 = require("@tradejs/core/indicators");
|
|
7498
|
+
var import_data = require("@tradejs/core/data");
|
|
7427
7499
|
var import_strategies = require("@tradejs/core/strategies");
|
|
7428
7500
|
var import_constants2 = require("@tradejs/core/constants");
|
|
7429
7501
|
var import_timescale = require("@tradejs/infra/timescale");
|
|
7430
7502
|
var import_logger4 = require("@tradejs/infra/logger");
|
|
7431
|
-
var
|
|
7503
|
+
var STORED_INTERVALS = ["15m", "1h"];
|
|
7432
7504
|
var CONTEXT_INTERVALS = ["15m", "1h"];
|
|
7433
7505
|
var DEFAULT_LOOKBACK_HOURS = 48;
|
|
7434
7506
|
var PRIMARY_DERIVATIVES_REFERENCE_SYMBOL = import_constants2.DERIVATIVES_CONTEXT_BASE_REFERENCE_SYMBOLS[0];
|
|
@@ -7454,9 +7526,12 @@ var parseLookbackMs = () => {
|
|
|
7454
7526
|
const normalizedHours = Number.isFinite(hours) && hours > 0 ? hours : DEFAULT_LOOKBACK_HOURS;
|
|
7455
7527
|
return normalizedHours * 60 * 60 * 1e3;
|
|
7456
7528
|
};
|
|
7457
|
-
var
|
|
7529
|
+
var withHourlyFallbackRows = (rowsByInterval) => ({
|
|
7458
7530
|
"15m": rowsByInterval["15m"] ?? [],
|
|
7459
|
-
"1h": (0, import_indicators2.
|
|
7531
|
+
"1h": (0, import_indicators2.buildCoinalyzeHourlyRowsWithFallback)({
|
|
7532
|
+
rows15m: rowsByInterval["15m"],
|
|
7533
|
+
fallbackRows1h: rowsByInterval["1h"]
|
|
7534
|
+
})
|
|
7460
7535
|
});
|
|
7461
7536
|
var getDerivativesContextReferenceSymbols = () => [
|
|
7462
7537
|
...(0, import_constants2.resolveDerivativesContextReferenceSymbols)(
|
|
@@ -7580,12 +7655,17 @@ var enrichSignalWithDerivativesContext = async (params) => {
|
|
|
7580
7655
|
const referenceSymbols = getDerivativesContextReferenceSymbols();
|
|
7581
7656
|
const targetSymbol = normalizeSymbol(signal.symbol);
|
|
7582
7657
|
const lookbackMs = parseLookbackMs();
|
|
7658
|
+
const decisionTimeMs = signal.timestamp + (0, import_data.intervalToMs)(signal.interval);
|
|
7659
|
+
const derivativesEndMs = (0, import_indicators2.getLastClosedDerivativesBarStartMs)(
|
|
7660
|
+
decisionTimeMs,
|
|
7661
|
+
"15m"
|
|
7662
|
+
);
|
|
7583
7663
|
const contexts = await Promise.all(
|
|
7584
7664
|
referenceSymbols.map(async (symbol) => {
|
|
7585
7665
|
const rowsByInterval = await (0, import_timescale.getDerivativesWindow)({
|
|
7586
7666
|
symbol,
|
|
7587
|
-
intervals:
|
|
7588
|
-
endMs:
|
|
7667
|
+
intervals: STORED_INTERVALS,
|
|
7668
|
+
endMs: derivativesEndMs,
|
|
7589
7669
|
lookbackMs
|
|
7590
7670
|
});
|
|
7591
7671
|
return [
|
|
@@ -7593,8 +7673,8 @@ var enrichSignalWithDerivativesContext = async (params) => {
|
|
|
7593
7673
|
(0, import_indicators2.buildDerivativesContext)({
|
|
7594
7674
|
symbol,
|
|
7595
7675
|
direction: signal.direction,
|
|
7596
|
-
timestamp:
|
|
7597
|
-
rowsByInterval:
|
|
7676
|
+
timestamp: derivativesEndMs,
|
|
7677
|
+
rowsByInterval: withHourlyFallbackRows(rowsByInterval),
|
|
7598
7678
|
priceChangePct1h: getSignalPriceChangePct1h(signal),
|
|
7599
7679
|
intervals: CONTEXT_INTERVALS
|
|
7600
7680
|
})
|
|
@@ -7612,15 +7692,15 @@ var enrichSignalWithDerivativesContext = async (params) => {
|
|
|
7612
7692
|
const fetchedTargetContext = shouldFetchTargetContext ? await (async () => {
|
|
7613
7693
|
const rowsByInterval = await (0, import_timescale.getDerivativesWindow)({
|
|
7614
7694
|
symbol: targetSymbol,
|
|
7615
|
-
intervals:
|
|
7616
|
-
endMs:
|
|
7695
|
+
intervals: STORED_INTERVALS,
|
|
7696
|
+
endMs: derivativesEndMs,
|
|
7617
7697
|
lookbackMs
|
|
7618
7698
|
});
|
|
7619
7699
|
const context = (0, import_indicators2.buildDerivativesContext)({
|
|
7620
7700
|
symbol: targetSymbol,
|
|
7621
7701
|
direction: signal.direction,
|
|
7622
|
-
timestamp:
|
|
7623
|
-
rowsByInterval:
|
|
7702
|
+
timestamp: derivativesEndMs,
|
|
7703
|
+
rowsByInterval: withHourlyFallbackRows(rowsByInterval),
|
|
7624
7704
|
priceChangePct1h: getSignalPriceChangePct1h(signal),
|
|
7625
7705
|
intervals: CONTEXT_INTERVALS
|
|
7626
7706
|
});
|
|
@@ -8624,12 +8704,14 @@ var executeEntryOrder = async ({
|
|
|
8624
8704
|
timestamp,
|
|
8625
8705
|
takeProfits,
|
|
8626
8706
|
stopLossPrice,
|
|
8707
|
+
positionIntent = "open",
|
|
8627
8708
|
signal,
|
|
8628
8709
|
beforePlaceOrder,
|
|
8629
8710
|
recordRuntimeTrade = true,
|
|
8630
8711
|
leverage
|
|
8631
8712
|
}) => {
|
|
8632
8713
|
await beforePlaceOrder?.();
|
|
8714
|
+
const previousPosition = positionIntent === "increase" ? await connector.getPosition(symbol) : null;
|
|
8633
8715
|
const orderId = signal.orderId || createRuntimeOrderId(signal.strategy);
|
|
8634
8716
|
const signalTimestamp = signal.timestamp;
|
|
8635
8717
|
const signalClosePrice = currentPrice;
|
|
@@ -8644,6 +8726,7 @@ var executeEntryOrder = async ({
|
|
|
8644
8726
|
qty,
|
|
8645
8727
|
price: currentPrice,
|
|
8646
8728
|
isLimit: false,
|
|
8729
|
+
positionIntent,
|
|
8647
8730
|
timestamp,
|
|
8648
8731
|
direction,
|
|
8649
8732
|
...typeof leverage === "number" && Number.isFinite(leverage) ? { leverage } : {},
|
|
@@ -8654,27 +8737,36 @@ var executeEntryOrder = async ({
|
|
|
8654
8737
|
const placedQty = typeof signal.orderQty === "number" && Number.isFinite(signal.orderQty) && signal.orderQty > 0 ? signal.orderQty : qty;
|
|
8655
8738
|
const currentPosition = await connector.getPosition(symbol);
|
|
8656
8739
|
const fillTime = Date.now();
|
|
8657
|
-
const
|
|
8658
|
-
const
|
|
8659
|
-
|
|
8660
|
-
|
|
8661
|
-
|
|
8662
|
-
|
|
8663
|
-
|
|
8740
|
+
const isPositionIncrease = positionIntent === "increase" && previousPosition?.direction === direction && Number.isFinite(previousPosition.qty) && previousPosition.qty > 0;
|
|
8741
|
+
const hasRefreshedIncreasedPosition = Boolean(
|
|
8742
|
+
isPositionIncrease && previousPosition && currentPosition?.qty && currentPosition.qty > previousPosition.qty
|
|
8743
|
+
);
|
|
8744
|
+
const hasUsableCurrentPosition = Boolean(
|
|
8745
|
+
currentPosition && Number.isFinite(currentPosition.price) && Number.isFinite(currentPosition.qty) && (!isPositionIncrease || hasRefreshedIncreasedPosition)
|
|
8746
|
+
);
|
|
8747
|
+
const resultingEntryPrice = hasUsableCurrentPosition && currentPosition ? currentPosition.price : isPositionIncrease && previousPosition ? (previousPosition.price * previousPosition.qty + currentPrice * placedQty) / (previousPosition.qty + placedQty) : currentPrice;
|
|
8748
|
+
const resultingQty = hasUsableCurrentPosition && currentPosition ? currentPosition.qty : isPositionIncrease && previousPosition ? previousPosition.qty + placedQty : placedQty;
|
|
8749
|
+
const filledQty = isPositionIncrease && previousPosition ? hasRefreshedIncreasedPosition && currentPosition ? currentPosition.qty - previousPosition.qty : placedQty : resultingQty;
|
|
8750
|
+
const fillPrice = isPositionIncrease && previousPosition && hasRefreshedIncreasedPosition && currentPosition ? (resultingEntryPrice * currentPosition.qty - previousPosition.price * previousPosition.qty) / (currentPosition.qty - previousPosition.qty) : isPositionIncrease ? currentPrice : resultingEntryPrice;
|
|
8751
|
+
const fillSource = hasUsableCurrentPosition ? "exchange_position" : orderPlaced ? "requested_price" : "unknown";
|
|
8752
|
+
const estimatedOpenFee = fillPrice * filledQty * import_constants3.FEE_PERCENT;
|
|
8753
|
+
signal.prices.currentPrice = fillPrice;
|
|
8754
|
+
signal.orderQty = filledQty;
|
|
8755
|
+
signal.orderValue = filledQty * fillPrice;
|
|
8664
8756
|
if (orderPlaced) {
|
|
8665
8757
|
try {
|
|
8666
8758
|
await applyProtectiveOrders({
|
|
8667
8759
|
connector,
|
|
8668
8760
|
symbol,
|
|
8669
8761
|
direction,
|
|
8670
|
-
qty:
|
|
8762
|
+
qty: resultingQty,
|
|
8671
8763
|
takeProfits,
|
|
8672
8764
|
stopLossPrice
|
|
8673
8765
|
});
|
|
8674
8766
|
} catch (error) {
|
|
8675
8767
|
await connector.closePosition({
|
|
8676
8768
|
symbol,
|
|
8677
|
-
price:
|
|
8769
|
+
price: resultingEntryPrice,
|
|
8678
8770
|
timestamp,
|
|
8679
8771
|
direction,
|
|
8680
8772
|
signal
|
|
@@ -8687,7 +8779,7 @@ var executeEntryOrder = async ({
|
|
|
8687
8779
|
if (orderPlaced) {
|
|
8688
8780
|
signal.orderFailureReason = void 0;
|
|
8689
8781
|
}
|
|
8690
|
-
if (orderPlaced && recordRuntimeTrade) {
|
|
8782
|
+
if (orderPlaced && recordRuntimeTrade && !isPositionIncrease) {
|
|
8691
8783
|
await recordRuntimeTradeOpen({
|
|
8692
8784
|
userName,
|
|
8693
8785
|
orderId,
|
|
@@ -8696,8 +8788,8 @@ var executeEntryOrder = async ({
|
|
|
8696
8788
|
symbol,
|
|
8697
8789
|
interval: signal.interval,
|
|
8698
8790
|
direction,
|
|
8699
|
-
qty:
|
|
8700
|
-
entryPrice,
|
|
8791
|
+
qty: resultingQty,
|
|
8792
|
+
entryPrice: resultingEntryPrice,
|
|
8701
8793
|
signalTimestamp,
|
|
8702
8794
|
signalClosePrice,
|
|
8703
8795
|
arrivalSnapshotTime: arrivalSnapshot.arrivalSnapshotTime,
|
|
@@ -8708,7 +8800,7 @@ var executeEntryOrder = async ({
|
|
|
8708
8800
|
spreadBps: arrivalSnapshot.spreadBps,
|
|
8709
8801
|
orderSubmitTime,
|
|
8710
8802
|
orderAckTime,
|
|
8711
|
-
fillAvgPrice:
|
|
8803
|
+
fillAvgPrice: fillPrice,
|
|
8712
8804
|
fillSource,
|
|
8713
8805
|
fillTime,
|
|
8714
8806
|
telemetryQuality: resolveRuntimeTelemetryQuality({
|
|
@@ -8716,7 +8808,7 @@ var executeEntryOrder = async ({
|
|
|
8716
8808
|
arrivalMid: arrivalSnapshot.arrivalMid,
|
|
8717
8809
|
orderSubmitTime,
|
|
8718
8810
|
orderAckTime,
|
|
8719
|
-
fillAvgPrice:
|
|
8811
|
+
fillAvgPrice: fillPrice,
|
|
8720
8812
|
fillTime
|
|
8721
8813
|
}),
|
|
8722
8814
|
fee: estimatedOpenFee,
|
|
@@ -8732,10 +8824,26 @@ var executeEntryOrder = async ({
|
|
|
8732
8824
|
...signal.aiAnalysis ? { aiAnalysis: signal.aiAnalysis } : {}
|
|
8733
8825
|
});
|
|
8734
8826
|
}
|
|
8735
|
-
if (
|
|
8827
|
+
if (orderPlaced && recordRuntimeTrade && isPositionIncrease) {
|
|
8828
|
+
await recordRuntimeTradeIncrease({
|
|
8829
|
+
userName,
|
|
8830
|
+
strategy: signal.strategy,
|
|
8831
|
+
symbol,
|
|
8832
|
+
direction,
|
|
8833
|
+
resultingQty,
|
|
8834
|
+
resultingEntryPrice,
|
|
8835
|
+
addedQty: filledQty,
|
|
8836
|
+
addedEntryPrice: fillPrice,
|
|
8837
|
+
entryTimestamp: timestamp,
|
|
8838
|
+
fee: estimatedOpenFee,
|
|
8839
|
+
accountId: signal.accountId,
|
|
8840
|
+
deploymentId: signal.deploymentId
|
|
8841
|
+
});
|
|
8842
|
+
}
|
|
8843
|
+
if (hasUsableCurrentPosition && currentPosition?.price) {
|
|
8736
8844
|
return currentPosition.price;
|
|
8737
8845
|
}
|
|
8738
|
-
return
|
|
8846
|
+
return resultingEntryPrice;
|
|
8739
8847
|
};
|
|
8740
8848
|
var updatePositionProtection = async ({
|
|
8741
8849
|
connector,
|
|
@@ -8983,7 +9091,7 @@ var resolveBacktestExecutionDelayMs = (value, fallbackDelayMs) => {
|
|
|
8983
9091
|
};
|
|
8984
9092
|
var safeIntervalToMs = (interval) => {
|
|
8985
9093
|
try {
|
|
8986
|
-
return (0,
|
|
9094
|
+
return (0, import_data2.intervalToMs)(interval);
|
|
8987
9095
|
} catch {
|
|
8988
9096
|
return null;
|
|
8989
9097
|
}
|
|
@@ -9508,6 +9616,7 @@ var executeEntryDecision = async ({
|
|
|
9508
9616
|
timestamp: decision.entryContext.timestamp,
|
|
9509
9617
|
takeProfits: decision.orderPlan.takeProfits,
|
|
9510
9618
|
stopLossPrice: decision.orderPlan.stopLossPrice,
|
|
9619
|
+
positionIntent: decision.orderPlan.positionIntent,
|
|
9511
9620
|
...Number.isFinite(Number(hookCtx.strategyConfig.LEVERAGE)) ? { leverage: Number(hookCtx.strategyConfig.LEVERAGE) } : {},
|
|
9512
9621
|
signal,
|
|
9513
9622
|
beforePlaceOrder,
|
|
@@ -9539,6 +9648,7 @@ var executeEntryDecision = async ({
|
|
|
9539
9648
|
price: decision.entryContext.prices.currentPrice,
|
|
9540
9649
|
timestamp: decision.entryContext.timestamp,
|
|
9541
9650
|
direction: decision.entryContext.direction,
|
|
9651
|
+
positionIntent: decision.orderPlan.positionIntent,
|
|
9542
9652
|
...Number.isFinite(Number(hookCtx.strategyConfig.LEVERAGE)) ? { leverage: Number(hookCtx.strategyConfig.LEVERAGE) } : {}
|
|
9543
9653
|
});
|
|
9544
9654
|
if (!orderPlaced) {
|
package/dist/strategies.mjs
CHANGED
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
enrichSignalWithBinanceMarketContext,
|
|
4
4
|
enrichSignalWithCoinMarketCapContext,
|
|
5
5
|
enrichSignalWithDerivativesContext
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-2DZCHRP6.mjs";
|
|
7
7
|
import {
|
|
8
8
|
require_lodash
|
|
9
9
|
} from "./chunk-KZDHZ56N.mjs";
|
|
@@ -119,6 +119,10 @@ var recordRuntimeTradeOpen = async (params) => {
|
|
|
119
119
|
}
|
|
120
120
|
const record = {
|
|
121
121
|
...params,
|
|
122
|
+
entryCount: 1,
|
|
123
|
+
lastEntryPrice: params.entryPrice,
|
|
124
|
+
lastEntryQty: params.qty,
|
|
125
|
+
lastEntryTimestamp: params.entryTimestamp,
|
|
122
126
|
status: "active",
|
|
123
127
|
currentPrice: params.entryPrice,
|
|
124
128
|
currentPnl: 0,
|
|
@@ -155,6 +159,73 @@ var recordRuntimeTradeOpen = async (params) => {
|
|
|
155
159
|
}
|
|
156
160
|
return record;
|
|
157
161
|
};
|
|
162
|
+
var recordRuntimeTradeIncrease = async (params) => {
|
|
163
|
+
const {
|
|
164
|
+
userName,
|
|
165
|
+
strategy,
|
|
166
|
+
symbol,
|
|
167
|
+
direction,
|
|
168
|
+
resultingQty,
|
|
169
|
+
resultingEntryPrice,
|
|
170
|
+
addedQty,
|
|
171
|
+
addedEntryPrice,
|
|
172
|
+
entryTimestamp,
|
|
173
|
+
fee,
|
|
174
|
+
accountId,
|
|
175
|
+
deploymentId
|
|
176
|
+
} = params;
|
|
177
|
+
if (!userName) {
|
|
178
|
+
return null;
|
|
179
|
+
}
|
|
180
|
+
const existing = await getActiveRuntimeTrade({
|
|
181
|
+
userName,
|
|
182
|
+
symbol,
|
|
183
|
+
accountId,
|
|
184
|
+
deploymentId
|
|
185
|
+
});
|
|
186
|
+
if (!existing || existing.strategy !== strategy || existing.direction !== direction) {
|
|
187
|
+
return null;
|
|
188
|
+
}
|
|
189
|
+
const addedFee = typeof fee === "number" && Number.isFinite(fee) ? fee : 0;
|
|
190
|
+
const openFee = (existing.openFee ?? existing.fee ?? 0) + addedFee;
|
|
191
|
+
const totalFee = (existing.totalFee ?? existing.fee ?? 0) + addedFee;
|
|
192
|
+
const next = {
|
|
193
|
+
...existing,
|
|
194
|
+
qty: resultingQty,
|
|
195
|
+
entryPrice: resultingEntryPrice,
|
|
196
|
+
entryCount: Math.max(1, existing.entryCount ?? 1) + 1,
|
|
197
|
+
lastEntryPrice: addedEntryPrice,
|
|
198
|
+
lastEntryQty: addedQty,
|
|
199
|
+
lastEntryTimestamp: entryTimestamp,
|
|
200
|
+
currentPrice: resultingEntryPrice,
|
|
201
|
+
currentPnl: 0,
|
|
202
|
+
fee: openFee,
|
|
203
|
+
openFee,
|
|
204
|
+
totalFee,
|
|
205
|
+
lastSyncedAt: now()
|
|
206
|
+
};
|
|
207
|
+
const dayKey = getRuntimeStorageDayKey(existing.entryTimestamp);
|
|
208
|
+
try {
|
|
209
|
+
await Promise.all([
|
|
210
|
+
setData(redisKeys.runtimeTrade(userName, existing.orderId), next, {
|
|
211
|
+
expire: 0
|
|
212
|
+
}),
|
|
213
|
+
setHashJsonField(
|
|
214
|
+
redisKeys.runtimeTradeBucket(userName, dayKey),
|
|
215
|
+
existing.orderId,
|
|
216
|
+
next,
|
|
217
|
+
{ expire: 0 }
|
|
218
|
+
)
|
|
219
|
+
]);
|
|
220
|
+
} catch (error) {
|
|
221
|
+
logger.error(
|
|
222
|
+
"runtime trade increase journal failed: %s %s",
|
|
223
|
+
symbol,
|
|
224
|
+
error?.message || String(error)
|
|
225
|
+
);
|
|
226
|
+
}
|
|
227
|
+
return next;
|
|
228
|
+
};
|
|
158
229
|
var getActiveRuntimeTrade = async (params) => {
|
|
159
230
|
const { userName, symbol, accountId, deploymentId } = params;
|
|
160
231
|
if (!userName) {
|
|
@@ -496,12 +567,14 @@ var executeEntryOrder = async ({
|
|
|
496
567
|
timestamp,
|
|
497
568
|
takeProfits,
|
|
498
569
|
stopLossPrice,
|
|
570
|
+
positionIntent = "open",
|
|
499
571
|
signal,
|
|
500
572
|
beforePlaceOrder,
|
|
501
573
|
recordRuntimeTrade = true,
|
|
502
574
|
leverage
|
|
503
575
|
}) => {
|
|
504
576
|
await beforePlaceOrder?.();
|
|
577
|
+
const previousPosition = positionIntent === "increase" ? await connector.getPosition(symbol) : null;
|
|
505
578
|
const orderId = signal.orderId || createRuntimeOrderId(signal.strategy);
|
|
506
579
|
const signalTimestamp = signal.timestamp;
|
|
507
580
|
const signalClosePrice = currentPrice;
|
|
@@ -516,6 +589,7 @@ var executeEntryOrder = async ({
|
|
|
516
589
|
qty,
|
|
517
590
|
price: currentPrice,
|
|
518
591
|
isLimit: false,
|
|
592
|
+
positionIntent,
|
|
519
593
|
timestamp,
|
|
520
594
|
direction,
|
|
521
595
|
...typeof leverage === "number" && Number.isFinite(leverage) ? { leverage } : {},
|
|
@@ -526,27 +600,36 @@ var executeEntryOrder = async ({
|
|
|
526
600
|
const placedQty = typeof signal.orderQty === "number" && Number.isFinite(signal.orderQty) && signal.orderQty > 0 ? signal.orderQty : qty;
|
|
527
601
|
const currentPosition = await connector.getPosition(symbol);
|
|
528
602
|
const fillTime = Date.now();
|
|
529
|
-
const
|
|
530
|
-
const
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
603
|
+
const isPositionIncrease = positionIntent === "increase" && previousPosition?.direction === direction && Number.isFinite(previousPosition.qty) && previousPosition.qty > 0;
|
|
604
|
+
const hasRefreshedIncreasedPosition = Boolean(
|
|
605
|
+
isPositionIncrease && previousPosition && currentPosition?.qty && currentPosition.qty > previousPosition.qty
|
|
606
|
+
);
|
|
607
|
+
const hasUsableCurrentPosition = Boolean(
|
|
608
|
+
currentPosition && Number.isFinite(currentPosition.price) && Number.isFinite(currentPosition.qty) && (!isPositionIncrease || hasRefreshedIncreasedPosition)
|
|
609
|
+
);
|
|
610
|
+
const resultingEntryPrice = hasUsableCurrentPosition && currentPosition ? currentPosition.price : isPositionIncrease && previousPosition ? (previousPosition.price * previousPosition.qty + currentPrice * placedQty) / (previousPosition.qty + placedQty) : currentPrice;
|
|
611
|
+
const resultingQty = hasUsableCurrentPosition && currentPosition ? currentPosition.qty : isPositionIncrease && previousPosition ? previousPosition.qty + placedQty : placedQty;
|
|
612
|
+
const filledQty = isPositionIncrease && previousPosition ? hasRefreshedIncreasedPosition && currentPosition ? currentPosition.qty - previousPosition.qty : placedQty : resultingQty;
|
|
613
|
+
const fillPrice = isPositionIncrease && previousPosition && hasRefreshedIncreasedPosition && currentPosition ? (resultingEntryPrice * currentPosition.qty - previousPosition.price * previousPosition.qty) / (currentPosition.qty - previousPosition.qty) : isPositionIncrease ? currentPrice : resultingEntryPrice;
|
|
614
|
+
const fillSource = hasUsableCurrentPosition ? "exchange_position" : orderPlaced ? "requested_price" : "unknown";
|
|
615
|
+
const estimatedOpenFee = fillPrice * filledQty * FEE_PERCENT;
|
|
616
|
+
signal.prices.currentPrice = fillPrice;
|
|
617
|
+
signal.orderQty = filledQty;
|
|
618
|
+
signal.orderValue = filledQty * fillPrice;
|
|
536
619
|
if (orderPlaced) {
|
|
537
620
|
try {
|
|
538
621
|
await applyProtectiveOrders({
|
|
539
622
|
connector,
|
|
540
623
|
symbol,
|
|
541
624
|
direction,
|
|
542
|
-
qty:
|
|
625
|
+
qty: resultingQty,
|
|
543
626
|
takeProfits,
|
|
544
627
|
stopLossPrice
|
|
545
628
|
});
|
|
546
629
|
} catch (error) {
|
|
547
630
|
await connector.closePosition({
|
|
548
631
|
symbol,
|
|
549
|
-
price:
|
|
632
|
+
price: resultingEntryPrice,
|
|
550
633
|
timestamp,
|
|
551
634
|
direction,
|
|
552
635
|
signal
|
|
@@ -559,7 +642,7 @@ var executeEntryOrder = async ({
|
|
|
559
642
|
if (orderPlaced) {
|
|
560
643
|
signal.orderFailureReason = void 0;
|
|
561
644
|
}
|
|
562
|
-
if (orderPlaced && recordRuntimeTrade) {
|
|
645
|
+
if (orderPlaced && recordRuntimeTrade && !isPositionIncrease) {
|
|
563
646
|
await recordRuntimeTradeOpen({
|
|
564
647
|
userName,
|
|
565
648
|
orderId,
|
|
@@ -568,8 +651,8 @@ var executeEntryOrder = async ({
|
|
|
568
651
|
symbol,
|
|
569
652
|
interval: signal.interval,
|
|
570
653
|
direction,
|
|
571
|
-
qty:
|
|
572
|
-
entryPrice,
|
|
654
|
+
qty: resultingQty,
|
|
655
|
+
entryPrice: resultingEntryPrice,
|
|
573
656
|
signalTimestamp,
|
|
574
657
|
signalClosePrice,
|
|
575
658
|
arrivalSnapshotTime: arrivalSnapshot.arrivalSnapshotTime,
|
|
@@ -580,7 +663,7 @@ var executeEntryOrder = async ({
|
|
|
580
663
|
spreadBps: arrivalSnapshot.spreadBps,
|
|
581
664
|
orderSubmitTime,
|
|
582
665
|
orderAckTime,
|
|
583
|
-
fillAvgPrice:
|
|
666
|
+
fillAvgPrice: fillPrice,
|
|
584
667
|
fillSource,
|
|
585
668
|
fillTime,
|
|
586
669
|
telemetryQuality: resolveRuntimeTelemetryQuality({
|
|
@@ -588,7 +671,7 @@ var executeEntryOrder = async ({
|
|
|
588
671
|
arrivalMid: arrivalSnapshot.arrivalMid,
|
|
589
672
|
orderSubmitTime,
|
|
590
673
|
orderAckTime,
|
|
591
|
-
fillAvgPrice:
|
|
674
|
+
fillAvgPrice: fillPrice,
|
|
592
675
|
fillTime
|
|
593
676
|
}),
|
|
594
677
|
fee: estimatedOpenFee,
|
|
@@ -604,10 +687,26 @@ var executeEntryOrder = async ({
|
|
|
604
687
|
...signal.aiAnalysis ? { aiAnalysis: signal.aiAnalysis } : {}
|
|
605
688
|
});
|
|
606
689
|
}
|
|
607
|
-
if (
|
|
690
|
+
if (orderPlaced && recordRuntimeTrade && isPositionIncrease) {
|
|
691
|
+
await recordRuntimeTradeIncrease({
|
|
692
|
+
userName,
|
|
693
|
+
strategy: signal.strategy,
|
|
694
|
+
symbol,
|
|
695
|
+
direction,
|
|
696
|
+
resultingQty,
|
|
697
|
+
resultingEntryPrice,
|
|
698
|
+
addedQty: filledQty,
|
|
699
|
+
addedEntryPrice: fillPrice,
|
|
700
|
+
entryTimestamp: timestamp,
|
|
701
|
+
fee: estimatedOpenFee,
|
|
702
|
+
accountId: signal.accountId,
|
|
703
|
+
deploymentId: signal.deploymentId
|
|
704
|
+
});
|
|
705
|
+
}
|
|
706
|
+
if (hasUsableCurrentPosition && currentPosition?.price) {
|
|
608
707
|
return currentPosition.price;
|
|
609
708
|
}
|
|
610
|
-
return
|
|
709
|
+
return resultingEntryPrice;
|
|
611
710
|
};
|
|
612
711
|
var updatePositionProtection = async ({
|
|
613
712
|
connector,
|
|
@@ -1354,6 +1453,7 @@ var executeEntryDecision = async ({
|
|
|
1354
1453
|
timestamp: decision.entryContext.timestamp,
|
|
1355
1454
|
takeProfits: decision.orderPlan.takeProfits,
|
|
1356
1455
|
stopLossPrice: decision.orderPlan.stopLossPrice,
|
|
1456
|
+
positionIntent: decision.orderPlan.positionIntent,
|
|
1357
1457
|
...Number.isFinite(Number(hookCtx.strategyConfig.LEVERAGE)) ? { leverage: Number(hookCtx.strategyConfig.LEVERAGE) } : {},
|
|
1358
1458
|
signal,
|
|
1359
1459
|
beforePlaceOrder,
|
|
@@ -1385,6 +1485,7 @@ var executeEntryDecision = async ({
|
|
|
1385
1485
|
price: decision.entryContext.prices.currentPrice,
|
|
1386
1486
|
timestamp: decision.entryContext.timestamp,
|
|
1387
1487
|
direction: decision.entryContext.direction,
|
|
1488
|
+
positionIntent: decision.orderPlan.positionIntent,
|
|
1388
1489
|
...Number.isFinite(Number(hookCtx.strategyConfig.LEVERAGE)) ? { leverage: Number(hookCtx.strategyConfig.LEVERAGE) } : {}
|
|
1389
1490
|
});
|
|
1390
1491
|
if (!orderPlaced) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tradejs/node",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.3",
|
|
4
4
|
"description": "Node-only runtime for the TradeJS TypeScript framework: strategies, backtests, Pine strategy loading, and plugin registries.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"tradejs",
|
|
@@ -67,9 +67,9 @@
|
|
|
67
67
|
"dependencies": {
|
|
68
68
|
"@langchain/core": "^1.1.42",
|
|
69
69
|
"@langchain/openai": "^1.4.5",
|
|
70
|
-
"@tradejs/core": "^2.0.
|
|
71
|
-
"@tradejs/infra": "^2.0.
|
|
72
|
-
"@tradejs/types": "^2.0.
|
|
70
|
+
"@tradejs/core": "^2.0.3",
|
|
71
|
+
"@tradejs/infra": "^2.0.3",
|
|
72
|
+
"@tradejs/types": "^2.0.3",
|
|
73
73
|
"chalk": "4.1.2",
|
|
74
74
|
"ioredis": "5.8.0",
|
|
75
75
|
"pinets": "0.8.12",
|