backtest-kit 9.0.1 → 9.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/build/index.cjs +169 -133
- package/build/index.mjs +169 -133
- package/package.json +1 -1
- package/types.d.ts +156 -132
package/build/index.mjs
CHANGED
|
@@ -1438,7 +1438,7 @@ class PersistRiskInstance {
|
|
|
1438
1438
|
*
|
|
1439
1439
|
* @returns Promise resolving to positions (empty array if none persisted)
|
|
1440
1440
|
*/
|
|
1441
|
-
async readPositionData() {
|
|
1441
|
+
async readPositionData(_when) {
|
|
1442
1442
|
if (await this._storage.hasValue(PersistRiskInstance.STORAGE_KEY)) {
|
|
1443
1443
|
return await this._storage.readValue(PersistRiskInstance.STORAGE_KEY);
|
|
1444
1444
|
}
|
|
@@ -1448,9 +1448,10 @@ class PersistRiskInstance {
|
|
|
1448
1448
|
* Writes the positions array using the fixed STORAGE_KEY.
|
|
1449
1449
|
*
|
|
1450
1450
|
* @param riskRow - Position entries to persist
|
|
1451
|
+
* @param when - Logical timestamp (reserved for API consistency; not used)
|
|
1451
1452
|
* @returns Promise that resolves when write is complete
|
|
1452
1453
|
*/
|
|
1453
|
-
async writePositionData(riskRow) {
|
|
1454
|
+
async writePositionData(riskRow, _when) {
|
|
1454
1455
|
await this._storage.writeValue(PersistRiskInstance.STORAGE_KEY, riskRow);
|
|
1455
1456
|
}
|
|
1456
1457
|
}
|
|
@@ -1475,12 +1476,12 @@ class PersistRiskDummyInstance {
|
|
|
1475
1476
|
* Always returns empty positions array.
|
|
1476
1477
|
* @returns Promise resolving to []
|
|
1477
1478
|
*/
|
|
1478
|
-
async readPositionData() { return []; }
|
|
1479
|
+
async readPositionData(_when) { return []; }
|
|
1479
1480
|
/**
|
|
1480
1481
|
* No-op write (discards positions).
|
|
1481
1482
|
* @returns Promise that resolves immediately
|
|
1482
1483
|
*/
|
|
1483
|
-
async writePositionData(_riskRow) { }
|
|
1484
|
+
async writePositionData(_riskRow, _when) { }
|
|
1484
1485
|
}
|
|
1485
1486
|
/**
|
|
1486
1487
|
* Utility class for managing risk active positions persistence.
|
|
@@ -1510,15 +1511,16 @@ class PersistRiskUtils {
|
|
|
1510
1511
|
*
|
|
1511
1512
|
* @param riskName - Risk profile identifier
|
|
1512
1513
|
* @param exchangeName - Exchange identifier
|
|
1514
|
+
* @param when - Logical timestamp at which the read is happening (reserved for API consistency)
|
|
1513
1515
|
* @returns Promise resolving to position entries (empty array if none)
|
|
1514
1516
|
*/
|
|
1515
|
-
this.readPositionData = async (riskName, exchangeName) => {
|
|
1517
|
+
this.readPositionData = async (riskName, exchangeName, when) => {
|
|
1516
1518
|
LOGGER_SERVICE$7.info(PERSIST_RISK_UTILS_METHOD_NAME_READ_DATA);
|
|
1517
1519
|
const key = `${riskName}:${exchangeName}`;
|
|
1518
1520
|
const isInitial = !this.getRiskStorage.has(key);
|
|
1519
1521
|
const instance = this.getRiskStorage(riskName, exchangeName);
|
|
1520
1522
|
await instance.waitForInit(isInitial);
|
|
1521
|
-
return instance.readPositionData();
|
|
1523
|
+
return instance.readPositionData(when);
|
|
1522
1524
|
};
|
|
1523
1525
|
/**
|
|
1524
1526
|
* Writes active positions for the given risk context.
|
|
@@ -1527,15 +1529,16 @@ class PersistRiskUtils {
|
|
|
1527
1529
|
* @param riskRow - Position entries to persist
|
|
1528
1530
|
* @param riskName - Risk profile identifier
|
|
1529
1531
|
* @param exchangeName - Exchange identifier
|
|
1532
|
+
* @param when - Logical timestamp this write belongs to (reserved for API consistency)
|
|
1530
1533
|
* @returns Promise that resolves when write is complete
|
|
1531
1534
|
*/
|
|
1532
|
-
this.writePositionData = async (riskRow, riskName, exchangeName) => {
|
|
1535
|
+
this.writePositionData = async (riskRow, riskName, exchangeName, when) => {
|
|
1533
1536
|
LOGGER_SERVICE$7.info(PERSIST_RISK_UTILS_METHOD_NAME_WRITE_DATA);
|
|
1534
1537
|
const key = `${riskName}:${exchangeName}`;
|
|
1535
1538
|
const isInitial = !this.getRiskStorage.has(key);
|
|
1536
1539
|
const instance = this.getRiskStorage(riskName, exchangeName);
|
|
1537
1540
|
await instance.waitForInit(isInitial);
|
|
1538
|
-
return instance.writePositionData(riskRow);
|
|
1541
|
+
return instance.writePositionData(riskRow, when);
|
|
1539
1542
|
};
|
|
1540
1543
|
}
|
|
1541
1544
|
/**
|
|
@@ -1829,7 +1832,7 @@ class PersistPartialInstance {
|
|
|
1829
1832
|
* @param signalId - Signal identifier
|
|
1830
1833
|
* @returns Promise resolving to partial data record (empty object if not found)
|
|
1831
1834
|
*/
|
|
1832
|
-
async readPartialData(signalId) {
|
|
1835
|
+
async readPartialData(signalId, _when) {
|
|
1833
1836
|
if (await this._storage.hasValue(signalId)) {
|
|
1834
1837
|
return await this._storage.readValue(signalId);
|
|
1835
1838
|
}
|
|
@@ -1840,9 +1843,10 @@ class PersistPartialInstance {
|
|
|
1840
1843
|
*
|
|
1841
1844
|
* @param data - Partial data record to persist
|
|
1842
1845
|
* @param signalId - Signal identifier
|
|
1846
|
+
* @param when - Logical timestamp (reserved for API consistency; not used)
|
|
1843
1847
|
* @returns Promise that resolves when write is complete
|
|
1844
1848
|
*/
|
|
1845
|
-
async writePartialData(data, signalId) {
|
|
1849
|
+
async writePartialData(data, signalId, _when) {
|
|
1846
1850
|
await this._storage.writeValue(signalId, data);
|
|
1847
1851
|
}
|
|
1848
1852
|
}
|
|
@@ -1865,12 +1869,12 @@ class PersistPartialDummyInstance {
|
|
|
1865
1869
|
* Always returns empty partial data record.
|
|
1866
1870
|
* @returns Promise resolving to {}
|
|
1867
1871
|
*/
|
|
1868
|
-
async readPartialData(_signalId) { return {}; }
|
|
1872
|
+
async readPartialData(_signalId, _when) { return {}; }
|
|
1869
1873
|
/**
|
|
1870
1874
|
* No-op write (discards partial data).
|
|
1871
1875
|
* @returns Promise that resolves immediately
|
|
1872
1876
|
*/
|
|
1873
|
-
async writePartialData(_data, _signalId) { }
|
|
1877
|
+
async writePartialData(_data, _signalId, _when) { }
|
|
1874
1878
|
}
|
|
1875
1879
|
/**
|
|
1876
1880
|
* Utility class for managing partial profit/loss levels persistence.
|
|
@@ -1903,15 +1907,16 @@ class PersistPartialUtils {
|
|
|
1903
1907
|
* @param strategyName - Strategy identifier
|
|
1904
1908
|
* @param signalId - Signal identifier
|
|
1905
1909
|
* @param exchangeName - Exchange identifier
|
|
1910
|
+
* @param when - Logical timestamp at which the read is happening (reserved for API consistency)
|
|
1906
1911
|
* @returns Promise resolving to partial data record (empty object if none)
|
|
1907
1912
|
*/
|
|
1908
|
-
this.readPartialData = async (symbol, strategyName, signalId, exchangeName) => {
|
|
1913
|
+
this.readPartialData = async (symbol, strategyName, signalId, exchangeName, when) => {
|
|
1909
1914
|
LOGGER_SERVICE$7.info(PERSIST_PARTIAL_UTILS_METHOD_NAME_READ_DATA);
|
|
1910
1915
|
const key = `${symbol}:${strategyName}:${exchangeName}`;
|
|
1911
1916
|
const isInitial = !this.getPartialStorage.has(key);
|
|
1912
1917
|
const instance = this.getPartialStorage(symbol, strategyName, exchangeName);
|
|
1913
1918
|
await instance.waitForInit(isInitial);
|
|
1914
|
-
return instance.readPartialData(signalId);
|
|
1919
|
+
return instance.readPartialData(signalId, when);
|
|
1915
1920
|
};
|
|
1916
1921
|
/**
|
|
1917
1922
|
* Writes partial data for the given context and signalId.
|
|
@@ -1922,15 +1927,16 @@ class PersistPartialUtils {
|
|
|
1922
1927
|
* @param strategyName - Strategy identifier
|
|
1923
1928
|
* @param signalId - Signal identifier
|
|
1924
1929
|
* @param exchangeName - Exchange identifier
|
|
1930
|
+
* @param when - Logical timestamp this write belongs to (reserved for API consistency)
|
|
1925
1931
|
* @returns Promise that resolves when write is complete
|
|
1926
1932
|
*/
|
|
1927
|
-
this.writePartialData = async (partialData, symbol, strategyName, signalId, exchangeName) => {
|
|
1933
|
+
this.writePartialData = async (partialData, symbol, strategyName, signalId, exchangeName, when) => {
|
|
1928
1934
|
LOGGER_SERVICE$7.info(PERSIST_PARTIAL_UTILS_METHOD_NAME_WRITE_DATA);
|
|
1929
1935
|
const key = `${symbol}:${strategyName}:${exchangeName}`;
|
|
1930
1936
|
const isInitial = !this.getPartialStorage.has(key);
|
|
1931
1937
|
const instance = this.getPartialStorage(symbol, strategyName, exchangeName);
|
|
1932
1938
|
await instance.waitForInit(isInitial);
|
|
1933
|
-
return instance.writePartialData(partialData, signalId);
|
|
1939
|
+
return instance.writePartialData(partialData, signalId, when);
|
|
1934
1940
|
};
|
|
1935
1941
|
}
|
|
1936
1942
|
/**
|
|
@@ -2029,7 +2035,7 @@ class PersistBreakevenInstance {
|
|
|
2029
2035
|
* @param signalId - Signal identifier
|
|
2030
2036
|
* @returns Promise resolving to breakeven data record (empty object if not found)
|
|
2031
2037
|
*/
|
|
2032
|
-
async readBreakevenData(signalId) {
|
|
2038
|
+
async readBreakevenData(signalId, _when) {
|
|
2033
2039
|
if (await this._storage.hasValue(signalId)) {
|
|
2034
2040
|
return await this._storage.readValue(signalId);
|
|
2035
2041
|
}
|
|
@@ -2040,9 +2046,10 @@ class PersistBreakevenInstance {
|
|
|
2040
2046
|
*
|
|
2041
2047
|
* @param data - Breakeven data record to persist
|
|
2042
2048
|
* @param signalId - Signal identifier
|
|
2049
|
+
* @param when - Logical timestamp (reserved for API consistency; not used)
|
|
2043
2050
|
* @returns Promise that resolves when write is complete
|
|
2044
2051
|
*/
|
|
2045
|
-
async writeBreakevenData(data, signalId) {
|
|
2052
|
+
async writeBreakevenData(data, signalId, _when) {
|
|
2046
2053
|
await this._storage.writeValue(signalId, data);
|
|
2047
2054
|
}
|
|
2048
2055
|
}
|
|
@@ -2065,12 +2072,12 @@ class PersistBreakevenDummyInstance {
|
|
|
2065
2072
|
* Always returns empty breakeven data record.
|
|
2066
2073
|
* @returns Promise resolving to {}
|
|
2067
2074
|
*/
|
|
2068
|
-
async readBreakevenData(_signalId) { return {}; }
|
|
2075
|
+
async readBreakevenData(_signalId, _when) { return {}; }
|
|
2069
2076
|
/**
|
|
2070
2077
|
* No-op write (discards breakeven data).
|
|
2071
2078
|
* @returns Promise that resolves immediately
|
|
2072
2079
|
*/
|
|
2073
|
-
async writeBreakevenData(_data, _signalId) { }
|
|
2080
|
+
async writeBreakevenData(_data, _signalId, _when) { }
|
|
2074
2081
|
}
|
|
2075
2082
|
/**
|
|
2076
2083
|
* Persistence utility class for breakeven state management.
|
|
@@ -2123,15 +2130,16 @@ class PersistBreakevenUtils {
|
|
|
2123
2130
|
* @param strategyName - Strategy identifier
|
|
2124
2131
|
* @param signalId - Signal identifier
|
|
2125
2132
|
* @param exchangeName - Exchange identifier
|
|
2133
|
+
* @param when - Logical timestamp at which the read is happening (reserved for API consistency)
|
|
2126
2134
|
* @returns Promise resolving to breakeven data record (empty object if none)
|
|
2127
2135
|
*/
|
|
2128
|
-
this.readBreakevenData = async (symbol, strategyName, signalId, exchangeName) => {
|
|
2136
|
+
this.readBreakevenData = async (symbol, strategyName, signalId, exchangeName, when) => {
|
|
2129
2137
|
LOGGER_SERVICE$7.info(PERSIST_BREAKEVEN_UTILS_METHOD_NAME_READ_DATA);
|
|
2130
2138
|
const key = `${symbol}:${strategyName}:${exchangeName}`;
|
|
2131
2139
|
const isInitial = !this.getBreakevenStorage.has(key);
|
|
2132
2140
|
const instance = this.getBreakevenStorage(symbol, strategyName, exchangeName);
|
|
2133
2141
|
await instance.waitForInit(isInitial);
|
|
2134
|
-
return instance.readBreakevenData(signalId);
|
|
2142
|
+
return instance.readBreakevenData(signalId, when);
|
|
2135
2143
|
};
|
|
2136
2144
|
/**
|
|
2137
2145
|
* Writes breakeven data for the given context and signalId.
|
|
@@ -2142,15 +2150,16 @@ class PersistBreakevenUtils {
|
|
|
2142
2150
|
* @param strategyName - Strategy identifier
|
|
2143
2151
|
* @param signalId - Signal identifier
|
|
2144
2152
|
* @param exchangeName - Exchange identifier
|
|
2153
|
+
* @param when - Logical timestamp this write belongs to (reserved for API consistency)
|
|
2145
2154
|
* @returns Promise that resolves when write is complete
|
|
2146
2155
|
*/
|
|
2147
|
-
this.writeBreakevenData = async (breakevenData, symbol, strategyName, signalId, exchangeName) => {
|
|
2156
|
+
this.writeBreakevenData = async (breakevenData, symbol, strategyName, signalId, exchangeName, when) => {
|
|
2148
2157
|
LOGGER_SERVICE$7.info(PERSIST_BREAKEVEN_UTILS_METHOD_NAME_WRITE_DATA);
|
|
2149
2158
|
const key = `${symbol}:${strategyName}:${exchangeName}`;
|
|
2150
2159
|
const isInitial = !this.getBreakevenStorage.has(key);
|
|
2151
2160
|
const instance = this.getBreakevenStorage(symbol, strategyName, exchangeName);
|
|
2152
2161
|
await instance.waitForInit(isInitial);
|
|
2153
|
-
return instance.writeBreakevenData(breakevenData, signalId);
|
|
2162
|
+
return instance.writeBreakevenData(breakevenData, signalId, when);
|
|
2154
2163
|
};
|
|
2155
2164
|
}
|
|
2156
2165
|
/**
|
|
@@ -3561,7 +3570,7 @@ class PersistMemoryInstance {
|
|
|
3561
3570
|
* @param memoryId - Memory entry identifier
|
|
3562
3571
|
* @returns Promise that resolves when write is complete
|
|
3563
3572
|
*/
|
|
3564
|
-
async writeMemoryData(data, memoryId) {
|
|
3573
|
+
async writeMemoryData(data, memoryId, _when) {
|
|
3565
3574
|
await this._storage.writeValue(memoryId, data);
|
|
3566
3575
|
}
|
|
3567
3576
|
/**
|
|
@@ -3626,7 +3635,7 @@ class PersistMemoryDummyInstance {
|
|
|
3626
3635
|
* No-op write (discards entry).
|
|
3627
3636
|
* @returns Promise that resolves immediately
|
|
3628
3637
|
*/
|
|
3629
|
-
async writeMemoryData(_data, _memoryId) { }
|
|
3638
|
+
async writeMemoryData(_data, _memoryId, _when) { }
|
|
3630
3639
|
/**
|
|
3631
3640
|
* No-op remove.
|
|
3632
3641
|
* @returns Promise that resolves immediately
|
|
@@ -3719,19 +3728,20 @@ class PersistMemoryUtils {
|
|
|
3719
3728
|
* Writes a memory entry for the given context.
|
|
3720
3729
|
* Lazily initializes the instance on first access.
|
|
3721
3730
|
*
|
|
3722
|
-
* @param data - Entry data to persist
|
|
3731
|
+
* @param data - Entry data to persist (already carries `data.when`)
|
|
3723
3732
|
* @param signalId - Signal identifier
|
|
3724
3733
|
* @param bucketName - Bucket name
|
|
3725
3734
|
* @param memoryId - Memory entry identifier
|
|
3735
|
+
* @param when - Logical timestamp this entry belongs to (duplicates `data.when` for API consistency)
|
|
3726
3736
|
* @returns Promise that resolves when write is complete
|
|
3727
3737
|
*/
|
|
3728
|
-
this.writeMemoryData = async (data, signalId, bucketName, memoryId) => {
|
|
3738
|
+
this.writeMemoryData = async (data, signalId, bucketName, memoryId, when) => {
|
|
3729
3739
|
LOGGER_SERVICE$7.info(PERSIST_MEMORY_UTILS_METHOD_NAME_WRITE_DATA, { signalId, bucketName, memoryId });
|
|
3730
3740
|
const key = `${signalId}:${bucketName}`;
|
|
3731
3741
|
const isInitial = !this.getMemoryStorage.has(key);
|
|
3732
3742
|
const instance = this.getMemoryStorage(signalId, bucketName);
|
|
3733
3743
|
await instance.waitForInit(isInitial);
|
|
3734
|
-
return instance.writeMemoryData(data, memoryId);
|
|
3744
|
+
return instance.writeMemoryData(data, memoryId, when);
|
|
3735
3745
|
};
|
|
3736
3746
|
/**
|
|
3737
3747
|
* Soft-deletes a memory entry for the given context.
|
|
@@ -3895,7 +3905,7 @@ class PersistRecentInstance {
|
|
|
3895
3905
|
* @param signalRow - Recent signal data to persist
|
|
3896
3906
|
* @returns Promise that resolves when write is complete
|
|
3897
3907
|
*/
|
|
3898
|
-
async writeRecentData(signalRow) {
|
|
3908
|
+
async writeRecentData(signalRow, _when) {
|
|
3899
3909
|
await this._storage.writeValue(this.symbol, signalRow);
|
|
3900
3910
|
}
|
|
3901
3911
|
}
|
|
@@ -3923,7 +3933,7 @@ class PersistRecentDummyInstance {
|
|
|
3923
3933
|
* No-op write (discards recent signal).
|
|
3924
3934
|
* @returns Promise that resolves immediately
|
|
3925
3935
|
*/
|
|
3926
|
-
async writeRecentData(_signalRow) { }
|
|
3936
|
+
async writeRecentData(_signalRow, _when) { }
|
|
3927
3937
|
}
|
|
3928
3938
|
/**
|
|
3929
3939
|
* Utility class for managing recent signal persistence.
|
|
@@ -3970,21 +3980,22 @@ class PersistRecentUtils {
|
|
|
3970
3980
|
* Writes the latest recent signal for the given context.
|
|
3971
3981
|
* Lazily initializes the instance on first access.
|
|
3972
3982
|
*
|
|
3973
|
-
* @param signalRow - Recent signal data to persist
|
|
3983
|
+
* @param signalRow - Recent signal data to persist (already carries `signalRow.timestamp`)
|
|
3974
3984
|
* @param symbol - Trading pair symbol
|
|
3975
3985
|
* @param strategyName - Strategy identifier
|
|
3976
3986
|
* @param exchangeName - Exchange identifier
|
|
3977
3987
|
* @param frameName - Frame identifier (may be empty)
|
|
3978
3988
|
* @param backtest - True for backtest mode, false for live mode
|
|
3989
|
+
* @param when - Logical timestamp this signal belongs to (duplicates `signalRow.timestamp` for API consistency)
|
|
3979
3990
|
* @returns Promise that resolves when write is complete
|
|
3980
3991
|
*/
|
|
3981
|
-
this.writeRecentData = async (signalRow, symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
3992
|
+
this.writeRecentData = async (signalRow, symbol, strategyName, exchangeName, frameName, backtest, when) => {
|
|
3982
3993
|
LOGGER_SERVICE$7.info(PERSIST_RECENT_UTILS_METHOD_NAME_WRITE_DATA);
|
|
3983
3994
|
const key = this.createKey(symbol, strategyName, exchangeName, frameName, backtest);
|
|
3984
3995
|
const isInitial = !this.getStorage.has(key);
|
|
3985
3996
|
const instance = this.getStorage(symbol, strategyName, exchangeName, frameName, backtest);
|
|
3986
3997
|
await instance.waitForInit(isInitial);
|
|
3987
|
-
return instance.writeRecentData(signalRow);
|
|
3998
|
+
return instance.writeRecentData(signalRow, when);
|
|
3988
3999
|
};
|
|
3989
4000
|
}
|
|
3990
4001
|
/**
|
|
@@ -4098,7 +4109,7 @@ class PersistStateInstance {
|
|
|
4098
4109
|
* @param data - State data to persist
|
|
4099
4110
|
* @returns Promise that resolves when write is complete
|
|
4100
4111
|
*/
|
|
4101
|
-
async writeStateData(data) {
|
|
4112
|
+
async writeStateData(data, _when) {
|
|
4102
4113
|
await this._storage.writeValue(this.bucketName, data);
|
|
4103
4114
|
}
|
|
4104
4115
|
/**
|
|
@@ -4131,7 +4142,7 @@ class PersistStateDummyInstance {
|
|
|
4131
4142
|
* No-op write (discards state).
|
|
4132
4143
|
* @returns Promise that resolves immediately
|
|
4133
4144
|
*/
|
|
4134
|
-
async writeStateData(_data) { }
|
|
4145
|
+
async writeStateData(_data, _when) { }
|
|
4135
4146
|
/**
|
|
4136
4147
|
* No-op dispose.
|
|
4137
4148
|
*/
|
|
@@ -4196,18 +4207,19 @@ class PersistStateUtils {
|
|
|
4196
4207
|
* Writes state for the given context.
|
|
4197
4208
|
* Lazily initializes the instance on first access.
|
|
4198
4209
|
*
|
|
4199
|
-
* @param data - State data to persist
|
|
4210
|
+
* @param data - State data to persist (already carries `data.when`)
|
|
4200
4211
|
* @param signalId - Signal identifier
|
|
4201
4212
|
* @param bucketName - Bucket name
|
|
4213
|
+
* @param when - Logical timestamp this value belongs to (duplicates `data.when` for API consistency)
|
|
4202
4214
|
* @returns Promise that resolves when write is complete
|
|
4203
4215
|
*/
|
|
4204
|
-
this.writeStateData = async (data, signalId, bucketName) => {
|
|
4216
|
+
this.writeStateData = async (data, signalId, bucketName, when) => {
|
|
4205
4217
|
LOGGER_SERVICE$7.info(PERSIST_STATE_UTILS_METHOD_NAME_WRITE_DATA, { signalId, bucketName });
|
|
4206
4218
|
const key = `${signalId}:${bucketName}`;
|
|
4207
4219
|
const isInitial = !this.getStateStorage.has(key);
|
|
4208
4220
|
const instance = this.getStateStorage(signalId, bucketName);
|
|
4209
4221
|
await instance.waitForInit(isInitial);
|
|
4210
|
-
return instance.writeStateData(data);
|
|
4222
|
+
return instance.writeStateData(data, when);
|
|
4211
4223
|
};
|
|
4212
4224
|
/**
|
|
4213
4225
|
* Switches to PersistStateDummyInstance (all operations are no-ops).
|
|
@@ -4317,7 +4329,7 @@ class PersistSessionInstance {
|
|
|
4317
4329
|
* @param data - Session data to persist
|
|
4318
4330
|
* @returns Promise that resolves when write is complete
|
|
4319
4331
|
*/
|
|
4320
|
-
async writeSessionData(data) {
|
|
4332
|
+
async writeSessionData(data, _when) {
|
|
4321
4333
|
await this._storage.writeValue(this.frameName, data);
|
|
4322
4334
|
}
|
|
4323
4335
|
/**
|
|
@@ -4350,7 +4362,7 @@ class PersistSessionDummyInstance {
|
|
|
4350
4362
|
* No-op write (discards session data).
|
|
4351
4363
|
* @returns Promise that resolves immediately
|
|
4352
4364
|
*/
|
|
4353
|
-
async writeSessionData(_data) { }
|
|
4365
|
+
async writeSessionData(_data, _when) { }
|
|
4354
4366
|
/**
|
|
4355
4367
|
* No-op dispose.
|
|
4356
4368
|
*/
|
|
@@ -4418,19 +4430,20 @@ class PersistSessionUtils {
|
|
|
4418
4430
|
* Writes session data for the given context.
|
|
4419
4431
|
* Lazily initializes the instance on first access.
|
|
4420
4432
|
*
|
|
4421
|
-
* @param data - Session data to persist
|
|
4433
|
+
* @param data - Session data to persist (already carries `data.when`)
|
|
4422
4434
|
* @param strategyName - Strategy identifier
|
|
4423
4435
|
* @param exchangeName - Exchange identifier
|
|
4424
4436
|
* @param frameName - Frame identifier
|
|
4437
|
+
* @param when - Logical timestamp this value belongs to (duplicates `data.when` for API consistency)
|
|
4425
4438
|
* @returns Promise that resolves when write is complete
|
|
4426
4439
|
*/
|
|
4427
|
-
this.writeSessionData = async (data, strategyName, exchangeName, frameName) => {
|
|
4440
|
+
this.writeSessionData = async (data, strategyName, exchangeName, frameName, when) => {
|
|
4428
4441
|
LOGGER_SERVICE$7.info(PERSIST_SESSION_UTILS_METHOD_NAME_WRITE_DATA, { strategyName, exchangeName, frameName });
|
|
4429
4442
|
const key = `${strategyName}:${exchangeName}:${frameName}`;
|
|
4430
4443
|
const isInitial = !this.getSessionStorage.has(key);
|
|
4431
4444
|
const instance = this.getSessionStorage(strategyName, exchangeName, frameName);
|
|
4432
4445
|
await instance.waitForInit(isInitial);
|
|
4433
|
-
return instance.writeSessionData(data);
|
|
4446
|
+
return instance.writeSessionData(data, when);
|
|
4434
4447
|
};
|
|
4435
4448
|
/**
|
|
4436
4449
|
* Switches to PersistSessionDummyInstance (all operations are no-ops).
|
|
@@ -14132,57 +14145,10 @@ const get = (object, path) => {
|
|
|
14132
14145
|
return pathArrayFlat.reduce((obj, key) => obj && obj[key], object);
|
|
14133
14146
|
};
|
|
14134
14147
|
|
|
14135
|
-
const MS_PER_MINUTE$6 = 60000;
|
|
14136
|
-
const INTERVAL_MINUTES$6 = {
|
|
14137
|
-
"1m": 1,
|
|
14138
|
-
"3m": 3,
|
|
14139
|
-
"5m": 5,
|
|
14140
|
-
"15m": 15,
|
|
14141
|
-
"30m": 30,
|
|
14142
|
-
"1h": 60,
|
|
14143
|
-
"2h": 120,
|
|
14144
|
-
"4h": 240,
|
|
14145
|
-
"6h": 360,
|
|
14146
|
-
"8h": 480,
|
|
14147
|
-
"1d": 1440,
|
|
14148
|
-
};
|
|
14149
|
-
/**
|
|
14150
|
-
* Aligns timestamp down to the nearest interval boundary.
|
|
14151
|
-
* For example, for 15m interval: 00:17 -> 00:15, 00:44 -> 00:30
|
|
14152
|
-
*
|
|
14153
|
-
* Candle timestamp convention:
|
|
14154
|
-
* - Candle timestamp = openTime (when candle opens)
|
|
14155
|
-
* - Candle with timestamp 00:00 covers period [00:00, 00:15) for 15m interval
|
|
14156
|
-
*
|
|
14157
|
-
* Adapter contract:
|
|
14158
|
-
* - Adapter must return candles with timestamp = openTime
|
|
14159
|
-
* - First returned candle.timestamp must equal aligned since
|
|
14160
|
-
* - Adapter must return exactly `limit` candles
|
|
14161
|
-
*
|
|
14162
|
-
* @param date - Date to align
|
|
14163
|
-
* @param interval - Candle interval (e.g., "1m", "15m", "1h")
|
|
14164
|
-
* @returns New Date aligned down to interval boundary
|
|
14165
|
-
*/
|
|
14166
|
-
const alignToInterval = (date, interval) => {
|
|
14167
|
-
const minutes = INTERVAL_MINUTES$6[interval];
|
|
14168
|
-
if (minutes === undefined) {
|
|
14169
|
-
throw new Error(`alignToInterval: unknown interval=${interval}`);
|
|
14170
|
-
}
|
|
14171
|
-
const intervalMs = minutes * MS_PER_MINUTE$6;
|
|
14172
|
-
return new Date(Math.floor(date.getTime() / intervalMs) * intervalMs);
|
|
14173
|
-
};
|
|
14174
|
-
|
|
14175
14148
|
/** Used to prevent race confition between concurent strategies */
|
|
14176
14149
|
const RISK_LOCK = new Lock();
|
|
14177
14150
|
/** Symbol indicating that positions need to be fetched from persistence */
|
|
14178
14151
|
const POSITION_NEED_FETCH = Symbol("risk-need-fetch");
|
|
14179
|
-
/** Get timestamp from execution context or fallback to aligned current time */
|
|
14180
|
-
const GET_CONTEXT_TIMESTAMP_FN = (self) => {
|
|
14181
|
-
if (ExecutionContextService.hasContext()) {
|
|
14182
|
-
return self.params.execution.context.when.getTime();
|
|
14183
|
-
}
|
|
14184
|
-
return alignToInterval(new Date(), "1m").getTime();
|
|
14185
|
-
};
|
|
14186
14152
|
/** Zero PNL constant for scheduled signals (which don't have priceOpen or PNL yet) */
|
|
14187
14153
|
const ZERO_PNL = { pnlPercentage: 0, priceOpen: 0, priceClose: 0, pnlCost: 0, pnlEntries: 0 };
|
|
14188
14154
|
/**
|
|
@@ -14308,7 +14274,7 @@ const CALL_ALLOWED_CALLBACKS_FN = trycatch(async (self, symbol, params) => {
|
|
|
14308
14274
|
*
|
|
14309
14275
|
* In backtest mode, initializes with empty Map. In live mode, reads from persist storage.
|
|
14310
14276
|
*/
|
|
14311
|
-
const WAIT_FOR_INIT_FN$3 = async (self) => {
|
|
14277
|
+
const WAIT_FOR_INIT_FN$3 = async (when, self) => {
|
|
14312
14278
|
self.params.logger.debug("ClientRisk waitForInit", {
|
|
14313
14279
|
backtest: self.params.backtest,
|
|
14314
14280
|
});
|
|
@@ -14316,7 +14282,7 @@ const WAIT_FOR_INIT_FN$3 = async (self) => {
|
|
|
14316
14282
|
self._activePositions = new Map();
|
|
14317
14283
|
return;
|
|
14318
14284
|
}
|
|
14319
|
-
const persistedPositions = await PersistRiskAdapter.readPositionData(self.params.riskName, self.params.exchangeName);
|
|
14285
|
+
const persistedPositions = await PersistRiskAdapter.readPositionData(self.params.riskName, self.params.exchangeName, when);
|
|
14320
14286
|
self._activePositions = new Map(persistedPositions);
|
|
14321
14287
|
};
|
|
14322
14288
|
/**
|
|
@@ -14345,7 +14311,7 @@ class ClientRisk {
|
|
|
14345
14311
|
* Uses singleshot pattern to ensure initialization happens exactly once.
|
|
14346
14312
|
* Skips persistence in backtest mode.
|
|
14347
14313
|
*/
|
|
14348
|
-
this.waitForInit = singleshot(async () => await WAIT_FOR_INIT_FN$3(this));
|
|
14314
|
+
this.waitForInit = singleshot(async (when) => await WAIT_FOR_INIT_FN$3(when, this));
|
|
14349
14315
|
/**
|
|
14350
14316
|
* Checks if a signal should be allowed based on risk limits.
|
|
14351
14317
|
*
|
|
@@ -14367,11 +14333,15 @@ class ClientRisk {
|
|
|
14367
14333
|
});
|
|
14368
14334
|
await RISK_LOCK.acquireLock();
|
|
14369
14335
|
try {
|
|
14336
|
+
const timestamp = await this.params.time.getTimestamp(params.symbol, {
|
|
14337
|
+
strategyName: params.strategyName,
|
|
14338
|
+
exchangeName: params.exchangeName,
|
|
14339
|
+
frameName: params.frameName,
|
|
14340
|
+
}, this.params.backtest);
|
|
14370
14341
|
if (this._activePositions === POSITION_NEED_FETCH) {
|
|
14371
|
-
await this.waitForInit();
|
|
14342
|
+
await this.waitForInit(new Date(timestamp));
|
|
14372
14343
|
}
|
|
14373
14344
|
const riskMap = this._activePositions;
|
|
14374
|
-
const timestamp = GET_CONTEXT_TIMESTAMP_FN(this);
|
|
14375
14345
|
const payload = {
|
|
14376
14346
|
...params,
|
|
14377
14347
|
currentSignal: TO_RISK_SIGNAL(params.currentSignal, params.currentPrice, timestamp),
|
|
@@ -14474,14 +14444,14 @@ class ClientRisk {
|
|
|
14474
14444
|
* Persists current active positions to disk.
|
|
14475
14445
|
* Skips in backtest mode.
|
|
14476
14446
|
*/
|
|
14477
|
-
async _updatePositions() {
|
|
14447
|
+
async _updatePositions(when) {
|
|
14478
14448
|
if (this.params.backtest) {
|
|
14479
14449
|
return;
|
|
14480
14450
|
}
|
|
14481
14451
|
if (this._activePositions === POSITION_NEED_FETCH) {
|
|
14482
|
-
await this.waitForInit();
|
|
14452
|
+
await this.waitForInit(when);
|
|
14483
14453
|
}
|
|
14484
|
-
await PersistRiskAdapter.writePositionData(Array.from(this._activePositions), this.params.riskName, this.params.exchangeName);
|
|
14454
|
+
await PersistRiskAdapter.writePositionData(Array.from(this._activePositions), this.params.riskName, this.params.exchangeName, when);
|
|
14485
14455
|
}
|
|
14486
14456
|
/**
|
|
14487
14457
|
* Registers a new opened signal.
|
|
@@ -14496,8 +14466,9 @@ class ClientRisk {
|
|
|
14496
14466
|
});
|
|
14497
14467
|
await RISK_LOCK.acquireLock();
|
|
14498
14468
|
try {
|
|
14469
|
+
const timestamp = await this.params.time.getTimestamp(symbol, context, this.params.backtest);
|
|
14499
14470
|
if (this._activePositions === POSITION_NEED_FETCH) {
|
|
14500
|
-
await this.waitForInit();
|
|
14471
|
+
await this.waitForInit(new Date(timestamp));
|
|
14501
14472
|
}
|
|
14502
14473
|
const key = CREATE_NAME_FN(context.strategyName, context.exchangeName, symbol);
|
|
14503
14474
|
const riskMap = this._activePositions;
|
|
@@ -14513,7 +14484,7 @@ class ClientRisk {
|
|
|
14513
14484
|
minuteEstimatedTime: positionData.minuteEstimatedTime,
|
|
14514
14485
|
openTimestamp: positionData.openTimestamp,
|
|
14515
14486
|
});
|
|
14516
|
-
await this._updatePositions();
|
|
14487
|
+
await this._updatePositions(new Date(timestamp));
|
|
14517
14488
|
}
|
|
14518
14489
|
finally {
|
|
14519
14490
|
await RISK_LOCK.releaseLock();
|
|
@@ -14531,13 +14502,14 @@ class ClientRisk {
|
|
|
14531
14502
|
});
|
|
14532
14503
|
await RISK_LOCK.acquireLock();
|
|
14533
14504
|
try {
|
|
14505
|
+
const timestamp = await this.params.time.getTimestamp(symbol, context, this.params.backtest);
|
|
14534
14506
|
if (this._activePositions === POSITION_NEED_FETCH) {
|
|
14535
|
-
await this.waitForInit();
|
|
14507
|
+
await this.waitForInit(new Date(timestamp));
|
|
14536
14508
|
}
|
|
14537
14509
|
const key = CREATE_NAME_FN(context.strategyName, context.exchangeName, symbol);
|
|
14538
14510
|
const riskMap = this._activePositions;
|
|
14539
14511
|
riskMap.delete(key);
|
|
14540
|
-
await this._updatePositions();
|
|
14512
|
+
await this._updatePositions(new Date(timestamp));
|
|
14541
14513
|
}
|
|
14542
14514
|
finally {
|
|
14543
14515
|
await RISK_LOCK.releaseLock();
|
|
@@ -14637,7 +14609,7 @@ class RiskConnectionService {
|
|
|
14637
14609
|
constructor() {
|
|
14638
14610
|
this.loggerService = inject(TYPES.loggerService);
|
|
14639
14611
|
this.riskSchemaService = inject(TYPES.riskSchemaService);
|
|
14640
|
-
this.
|
|
14612
|
+
this.timeMetaService = inject(TYPES.timeMetaService);
|
|
14641
14613
|
/**
|
|
14642
14614
|
* Action core service injected from DI container.
|
|
14643
14615
|
*/
|
|
@@ -14659,7 +14631,7 @@ class RiskConnectionService {
|
|
|
14659
14631
|
return new ClientRisk({
|
|
14660
14632
|
...schema,
|
|
14661
14633
|
logger: this.loggerService,
|
|
14662
|
-
|
|
14634
|
+
time: this.timeMetaService,
|
|
14663
14635
|
backtest,
|
|
14664
14636
|
exchangeName,
|
|
14665
14637
|
onRejected: CREATE_COMMIT_REJECTION_FN(this, exchangeName, frameName),
|
|
@@ -19650,8 +19622,8 @@ class BacktestLogicPrivateService {
|
|
|
19650
19622
|
}
|
|
19651
19623
|
|
|
19652
19624
|
const EMITTER_CHECK_INTERVAL = 5000;
|
|
19653
|
-
const MS_PER_MINUTE$
|
|
19654
|
-
const INTERVAL_MINUTES$
|
|
19625
|
+
const MS_PER_MINUTE$6 = 60000;
|
|
19626
|
+
const INTERVAL_MINUTES$6 = {
|
|
19655
19627
|
"1m": 1,
|
|
19656
19628
|
"3m": 3,
|
|
19657
19629
|
"5m": 5,
|
|
@@ -19666,7 +19638,7 @@ const INTERVAL_MINUTES$5 = {
|
|
|
19666
19638
|
};
|
|
19667
19639
|
const createEmitter = memoize(([interval]) => `${interval}`, (interval) => {
|
|
19668
19640
|
const tickSubject = new Subject();
|
|
19669
|
-
const intervalMs = INTERVAL_MINUTES$
|
|
19641
|
+
const intervalMs = INTERVAL_MINUTES$6[interval] * MS_PER_MINUTE$6;
|
|
19670
19642
|
{
|
|
19671
19643
|
let lastAligned = Math.floor(Date.now() / intervalMs) * intervalMs;
|
|
19672
19644
|
Source.fromInterval(EMITTER_CHECK_INTERVAL)
|
|
@@ -19693,6 +19665,46 @@ const waitForCandle = async (interval) => {
|
|
|
19693
19665
|
return emitter.toPromise();
|
|
19694
19666
|
};
|
|
19695
19667
|
|
|
19668
|
+
const MS_PER_MINUTE$5 = 60000;
|
|
19669
|
+
const INTERVAL_MINUTES$5 = {
|
|
19670
|
+
"1m": 1,
|
|
19671
|
+
"3m": 3,
|
|
19672
|
+
"5m": 5,
|
|
19673
|
+
"15m": 15,
|
|
19674
|
+
"30m": 30,
|
|
19675
|
+
"1h": 60,
|
|
19676
|
+
"2h": 120,
|
|
19677
|
+
"4h": 240,
|
|
19678
|
+
"6h": 360,
|
|
19679
|
+
"8h": 480,
|
|
19680
|
+
"1d": 1440,
|
|
19681
|
+
};
|
|
19682
|
+
/**
|
|
19683
|
+
* Aligns timestamp down to the nearest interval boundary.
|
|
19684
|
+
* For example, for 15m interval: 00:17 -> 00:15, 00:44 -> 00:30
|
|
19685
|
+
*
|
|
19686
|
+
* Candle timestamp convention:
|
|
19687
|
+
* - Candle timestamp = openTime (when candle opens)
|
|
19688
|
+
* - Candle with timestamp 00:00 covers period [00:00, 00:15) for 15m interval
|
|
19689
|
+
*
|
|
19690
|
+
* Adapter contract:
|
|
19691
|
+
* - Adapter must return candles with timestamp = openTime
|
|
19692
|
+
* - First returned candle.timestamp must equal aligned since
|
|
19693
|
+
* - Adapter must return exactly `limit` candles
|
|
19694
|
+
*
|
|
19695
|
+
* @param date - Date to align
|
|
19696
|
+
* @param interval - Candle interval (e.g., "1m", "15m", "1h")
|
|
19697
|
+
* @returns New Date aligned down to interval boundary
|
|
19698
|
+
*/
|
|
19699
|
+
const alignToInterval = (date, interval) => {
|
|
19700
|
+
const minutes = INTERVAL_MINUTES$5[interval];
|
|
19701
|
+
if (minutes === undefined) {
|
|
19702
|
+
throw new Error(`alignToInterval: unknown interval=${interval}`);
|
|
19703
|
+
}
|
|
19704
|
+
const intervalMs = minutes * MS_PER_MINUTE$5;
|
|
19705
|
+
return new Date(Math.floor(date.getTime() / intervalMs) * intervalMs);
|
|
19706
|
+
};
|
|
19707
|
+
|
|
19696
19708
|
/**
|
|
19697
19709
|
* Private service for live trading orchestration using async generators.
|
|
19698
19710
|
*
|
|
@@ -27191,7 +27203,7 @@ const HANDLE_PROFIT_FN = async (symbol, data, currentPrice, revenuePercent, back
|
|
|
27191
27203
|
}
|
|
27192
27204
|
}
|
|
27193
27205
|
if (shouldPersist) {
|
|
27194
|
-
await self._persistState(symbol, data.strategyName, data.exchangeName, self.params.signalId);
|
|
27206
|
+
await self._persistState(symbol, data.strategyName, data.exchangeName, data.frameName, self.params.signalId);
|
|
27195
27207
|
}
|
|
27196
27208
|
};
|
|
27197
27209
|
/**
|
|
@@ -27241,7 +27253,7 @@ const HANDLE_LOSS_FN = async (symbol, data, currentPrice, lossPercent, backtest,
|
|
|
27241
27253
|
}
|
|
27242
27254
|
}
|
|
27243
27255
|
if (shouldPersist) {
|
|
27244
|
-
await self._persistState(symbol, data.strategyName, data.exchangeName, self.params.signalId);
|
|
27256
|
+
await self._persistState(symbol, data.strategyName, data.exchangeName, data.frameName, self.params.signalId);
|
|
27245
27257
|
}
|
|
27246
27258
|
};
|
|
27247
27259
|
/**
|
|
@@ -27258,7 +27270,7 @@ const HANDLE_LOSS_FN = async (symbol, data, currentPrice, lossPercent, backtest,
|
|
|
27258
27270
|
* @param backtest - True if backtest mode, false if live mode
|
|
27259
27271
|
* @param self - ClientPartial instance reference
|
|
27260
27272
|
*/
|
|
27261
|
-
const WAIT_FOR_INIT_FN$1 = async (symbol, strategyName, exchangeName, backtest, self) => {
|
|
27273
|
+
const WAIT_FOR_INIT_FN$1 = async (symbol, strategyName, exchangeName, frameName, backtest, self) => {
|
|
27262
27274
|
self.params.logger.debug("ClientPartial waitForInit", {
|
|
27263
27275
|
symbol,
|
|
27264
27276
|
backtest,
|
|
@@ -27274,7 +27286,12 @@ const WAIT_FOR_INIT_FN$1 = async (symbol, strategyName, exchangeName, backtest,
|
|
|
27274
27286
|
self.params.logger.debug("ClientPartial waitForInit: skipping persist read in backtest mode");
|
|
27275
27287
|
return;
|
|
27276
27288
|
}
|
|
27277
|
-
const
|
|
27289
|
+
const timestamp = await self.params.time.getTimestamp(symbol, {
|
|
27290
|
+
strategyName,
|
|
27291
|
+
exchangeName,
|
|
27292
|
+
frameName,
|
|
27293
|
+
}, self.params.backtest);
|
|
27294
|
+
const partialData = await PersistPartialAdapter.readPartialData(symbol, strategyName, self.params.signalId, exchangeName, new Date(timestamp));
|
|
27278
27295
|
for (const [signalId, data] of Object.entries(partialData)) {
|
|
27279
27296
|
const state = {
|
|
27280
27297
|
profitLevels: new Set(data.profitLevels),
|
|
@@ -27382,7 +27399,7 @@ class ClientPartial {
|
|
|
27382
27399
|
* // Now profit()/loss() can be called
|
|
27383
27400
|
* ```
|
|
27384
27401
|
*/
|
|
27385
|
-
this.waitForInit = singleshot(async (symbol, strategyName, exchangeName, backtest) => await WAIT_FOR_INIT_FN$1(symbol, strategyName, exchangeName, backtest, this));
|
|
27402
|
+
this.waitForInit = singleshot(async (symbol, strategyName, exchangeName, frameName, backtest) => await WAIT_FOR_INIT_FN$1(symbol, strategyName, exchangeName, frameName, backtest, this));
|
|
27386
27403
|
}
|
|
27387
27404
|
/**
|
|
27388
27405
|
* Persists current partial state to disk.
|
|
@@ -27400,7 +27417,7 @@ class ClientPartial {
|
|
|
27400
27417
|
* @param signalId - Signal identifier
|
|
27401
27418
|
* @returns Promise that resolves when persistence is complete
|
|
27402
27419
|
*/
|
|
27403
|
-
async _persistState(symbol, strategyName, exchangeName, signalId) {
|
|
27420
|
+
async _persistState(symbol, strategyName, exchangeName, frameName, signalId) {
|
|
27404
27421
|
if (this.params.backtest) {
|
|
27405
27422
|
return;
|
|
27406
27423
|
}
|
|
@@ -27415,7 +27432,12 @@ class ClientPartial {
|
|
|
27415
27432
|
lossLevels: Array.from(state.lossLevels),
|
|
27416
27433
|
};
|
|
27417
27434
|
}
|
|
27418
|
-
await
|
|
27435
|
+
const timestamp = await this.params.time.getTimestamp(symbol, {
|
|
27436
|
+
strategyName,
|
|
27437
|
+
exchangeName,
|
|
27438
|
+
frameName,
|
|
27439
|
+
}, this.params.backtest);
|
|
27440
|
+
await PersistPartialAdapter.writePartialData(partialData, symbol, strategyName, signalId, exchangeName, new Date(timestamp));
|
|
27419
27441
|
}
|
|
27420
27442
|
/**
|
|
27421
27443
|
* Processes profit state and emits events for newly reached profit levels.
|
|
@@ -27540,7 +27562,7 @@ class ClientPartial {
|
|
|
27540
27562
|
throw new Error(`Signal ID mismatch: expected ${this.params.signalId}, got ${data.id}`);
|
|
27541
27563
|
}
|
|
27542
27564
|
this._states.delete(data.id);
|
|
27543
|
-
await this._persistState(symbol, data.strategyName, data.exchangeName, this.params.signalId);
|
|
27565
|
+
await this._persistState(symbol, data.strategyName, data.exchangeName, data.frameName, this.params.signalId);
|
|
27544
27566
|
}
|
|
27545
27567
|
}
|
|
27546
27568
|
|
|
@@ -27665,6 +27687,7 @@ class PartialConnectionService {
|
|
|
27665
27687
|
* Action core service injected from DI container.
|
|
27666
27688
|
*/
|
|
27667
27689
|
this.actionCoreService = inject(TYPES.actionCoreService);
|
|
27690
|
+
this.timeMetaService = inject(TYPES.timeMetaService);
|
|
27668
27691
|
/**
|
|
27669
27692
|
* Memoized factory function for ClientPartial instances.
|
|
27670
27693
|
*
|
|
@@ -27678,6 +27701,7 @@ class PartialConnectionService {
|
|
|
27678
27701
|
return new ClientPartial({
|
|
27679
27702
|
signalId,
|
|
27680
27703
|
logger: this.loggerService,
|
|
27704
|
+
time: this.timeMetaService,
|
|
27681
27705
|
backtest,
|
|
27682
27706
|
onProfit: CREATE_COMMIT_PROFIT_FN(this),
|
|
27683
27707
|
onLoss: CREATE_COMMIT_LOSS_FN(this),
|
|
@@ -27707,7 +27731,7 @@ class PartialConnectionService {
|
|
|
27707
27731
|
when,
|
|
27708
27732
|
});
|
|
27709
27733
|
const partial = this.getPartial(data.id, backtest);
|
|
27710
|
-
await partial.waitForInit(symbol, data.strategyName, data.exchangeName, backtest);
|
|
27734
|
+
await partial.waitForInit(symbol, data.strategyName, data.exchangeName, data.frameName, backtest);
|
|
27711
27735
|
return await partial.profit(symbol, data, currentPrice, revenuePercent, backtest, when);
|
|
27712
27736
|
};
|
|
27713
27737
|
/**
|
|
@@ -27734,7 +27758,7 @@ class PartialConnectionService {
|
|
|
27734
27758
|
when,
|
|
27735
27759
|
});
|
|
27736
27760
|
const partial = this.getPartial(data.id, backtest);
|
|
27737
|
-
await partial.waitForInit(symbol, data.strategyName, data.exchangeName, backtest);
|
|
27761
|
+
await partial.waitForInit(symbol, data.strategyName, data.exchangeName, data.frameName, backtest);
|
|
27738
27762
|
return await partial.loss(symbol, data, currentPrice, lossPercent, backtest, when);
|
|
27739
27763
|
};
|
|
27740
27764
|
/**
|
|
@@ -27762,7 +27786,7 @@ class PartialConnectionService {
|
|
|
27762
27786
|
backtest,
|
|
27763
27787
|
});
|
|
27764
27788
|
const partial = this.getPartial(data.id, backtest);
|
|
27765
|
-
await partial.waitForInit(symbol, data.strategyName, data.exchangeName, backtest);
|
|
27789
|
+
await partial.waitForInit(symbol, data.strategyName, data.exchangeName, data.frameName, backtest);
|
|
27766
27790
|
await partial.clear(symbol, data, priceClose, backtest);
|
|
27767
27791
|
const key = CREATE_KEY_FN$l(data.id, backtest);
|
|
27768
27792
|
this.getPartial.clear(key);
|
|
@@ -28488,7 +28512,7 @@ const HANDLE_BREAKEVEN_FN = async (symbol, data, currentPrice, backtest, when, s
|
|
|
28488
28512
|
// Emit event
|
|
28489
28513
|
await self.params.onBreakeven(symbol, data.strategyName, data.exchangeName, data.frameName, data, currentPrice, backtest, when.getTime());
|
|
28490
28514
|
// Persist state
|
|
28491
|
-
await self._persistState(symbol, data.strategyName, data.exchangeName, self.params.signalId);
|
|
28515
|
+
await self._persistState(symbol, data.strategyName, data.exchangeName, data.frameName, self.params.signalId);
|
|
28492
28516
|
return true;
|
|
28493
28517
|
};
|
|
28494
28518
|
/**
|
|
@@ -28503,7 +28527,7 @@ const HANDLE_BREAKEVEN_FN = async (symbol, data, currentPrice, backtest, when, s
|
|
|
28503
28527
|
* @param exchangeName - Exchange identifier
|
|
28504
28528
|
* @param self - ClientBreakeven instance reference
|
|
28505
28529
|
*/
|
|
28506
|
-
const WAIT_FOR_INIT_FN = async (symbol, strategyName, exchangeName, backtest, self) => {
|
|
28530
|
+
const WAIT_FOR_INIT_FN = async (symbol, strategyName, exchangeName, frameName, backtest, self) => {
|
|
28507
28531
|
self.params.logger.debug("ClientBreakeven waitForInit", {
|
|
28508
28532
|
symbol,
|
|
28509
28533
|
strategyName,
|
|
@@ -28519,7 +28543,12 @@ const WAIT_FOR_INIT_FN = async (symbol, strategyName, exchangeName, backtest, se
|
|
|
28519
28543
|
self.params.logger.debug("ClientBreakeven waitForInit: skipping persist read in backtest mode");
|
|
28520
28544
|
return;
|
|
28521
28545
|
}
|
|
28522
|
-
const
|
|
28546
|
+
const timestamp = await self.params.time.getTimestamp(symbol, {
|
|
28547
|
+
strategyName,
|
|
28548
|
+
exchangeName,
|
|
28549
|
+
frameName,
|
|
28550
|
+
}, self.params.backtest);
|
|
28551
|
+
const breakevenData = await PersistBreakevenAdapter.readBreakevenData(symbol, strategyName, self.params.signalId, exchangeName, new Date(timestamp));
|
|
28523
28552
|
for (const [signalId, data] of Object.entries(breakevenData)) {
|
|
28524
28553
|
const state = {
|
|
28525
28554
|
reached: data.reached,
|
|
@@ -28624,7 +28653,7 @@ class ClientBreakeven {
|
|
|
28624
28653
|
* // Now check() can be called
|
|
28625
28654
|
* ```
|
|
28626
28655
|
*/
|
|
28627
|
-
this.waitForInit = singleshot(async (symbol, strategyName, exchangeName, backtest) => await WAIT_FOR_INIT_FN(symbol, strategyName, exchangeName, backtest, this));
|
|
28656
|
+
this.waitForInit = singleshot(async (symbol, strategyName, exchangeName, frameName, backtest) => await WAIT_FOR_INIT_FN(symbol, strategyName, exchangeName, frameName, backtest, this));
|
|
28628
28657
|
}
|
|
28629
28658
|
/**
|
|
28630
28659
|
* Persists current breakeven state to disk.
|
|
@@ -28641,7 +28670,7 @@ class ClientBreakeven {
|
|
|
28641
28670
|
* @param signalId - Signal identifier
|
|
28642
28671
|
* @returns Promise that resolves when persistence is complete
|
|
28643
28672
|
*/
|
|
28644
|
-
async _persistState(symbol, strategyName, exchangeName, signalId) {
|
|
28673
|
+
async _persistState(symbol, strategyName, exchangeName, frameName, signalId) {
|
|
28645
28674
|
if (this.params.backtest) {
|
|
28646
28675
|
return;
|
|
28647
28676
|
}
|
|
@@ -28655,7 +28684,12 @@ class ClientBreakeven {
|
|
|
28655
28684
|
reached: state.reached,
|
|
28656
28685
|
};
|
|
28657
28686
|
}
|
|
28658
|
-
await
|
|
28687
|
+
const timestamp = await this.params.time.getTimestamp(symbol, {
|
|
28688
|
+
strategyName,
|
|
28689
|
+
exchangeName,
|
|
28690
|
+
frameName,
|
|
28691
|
+
}, this.params.backtest);
|
|
28692
|
+
await PersistBreakevenAdapter.writeBreakevenData(breakevenData, symbol, strategyName, signalId, exchangeName, new Date(timestamp));
|
|
28659
28693
|
}
|
|
28660
28694
|
/**
|
|
28661
28695
|
* Checks if breakeven should be triggered and emits event if conditions met.
|
|
@@ -28746,7 +28780,7 @@ class ClientBreakeven {
|
|
|
28746
28780
|
throw new Error(`Signal ID mismatch: expected ${this.params.signalId}, got ${data.id}`);
|
|
28747
28781
|
}
|
|
28748
28782
|
this._states.delete(data.id);
|
|
28749
|
-
await this._persistState(symbol, data.strategyName, data.exchangeName, this.params.signalId);
|
|
28783
|
+
await this._persistState(symbol, data.strategyName, data.exchangeName, data.frameName, this.params.signalId);
|
|
28750
28784
|
}
|
|
28751
28785
|
}
|
|
28752
28786
|
|
|
@@ -28835,6 +28869,7 @@ class BreakevenConnectionService {
|
|
|
28835
28869
|
* Action core service injected from DI container.
|
|
28836
28870
|
*/
|
|
28837
28871
|
this.actionCoreService = inject(TYPES.actionCoreService);
|
|
28872
|
+
this.timeMetaService = inject(TYPES.timeMetaService);
|
|
28838
28873
|
/**
|
|
28839
28874
|
* Memoized factory function for ClientBreakeven instances.
|
|
28840
28875
|
*
|
|
@@ -28848,6 +28883,7 @@ class BreakevenConnectionService {
|
|
|
28848
28883
|
return new ClientBreakeven({
|
|
28849
28884
|
signalId,
|
|
28850
28885
|
logger: this.loggerService,
|
|
28886
|
+
time: this.timeMetaService,
|
|
28851
28887
|
backtest,
|
|
28852
28888
|
onBreakeven: CREATE_COMMIT_BREAKEVEN_FN(this),
|
|
28853
28889
|
});
|
|
@@ -28874,7 +28910,7 @@ class BreakevenConnectionService {
|
|
|
28874
28910
|
when,
|
|
28875
28911
|
});
|
|
28876
28912
|
const breakeven = this.getBreakeven(data.id, backtest);
|
|
28877
|
-
await breakeven.waitForInit(symbol, data.strategyName, data.exchangeName, backtest);
|
|
28913
|
+
await breakeven.waitForInit(symbol, data.strategyName, data.exchangeName, data.frameName, backtest);
|
|
28878
28914
|
return await breakeven.check(symbol, data, currentPrice, backtest, when);
|
|
28879
28915
|
};
|
|
28880
28916
|
/**
|
|
@@ -28903,7 +28939,7 @@ class BreakevenConnectionService {
|
|
|
28903
28939
|
backtest,
|
|
28904
28940
|
});
|
|
28905
28941
|
const breakeven = this.getBreakeven(data.id, backtest);
|
|
28906
|
-
await breakeven.waitForInit(symbol, data.strategyName, data.exchangeName, backtest);
|
|
28942
|
+
await breakeven.waitForInit(symbol, data.strategyName, data.exchangeName, data.frameName, backtest);
|
|
28907
28943
|
await breakeven.clear(symbol, data, priceClose, backtest);
|
|
28908
28944
|
const key = CREATE_KEY_FN$i(data.id, backtest);
|
|
28909
28945
|
this.getBreakeven.clear(key);
|
|
@@ -48500,7 +48536,7 @@ class RecentPersistBacktestUtils {
|
|
|
48500
48536
|
backtest.loggerService.info(RECENT_PERSIST_BACKTEST_METHOD_NAME_HANDLE_ACTIVE_PING, {
|
|
48501
48537
|
signalId: event.data.id,
|
|
48502
48538
|
});
|
|
48503
|
-
await PersistRecentAdapter.writeRecentData(event.data, event.symbol, event.strategyName, event.exchangeName, event.data.frameName, event.backtest);
|
|
48539
|
+
await PersistRecentAdapter.writeRecentData(event.data, event.symbol, event.strategyName, event.exchangeName, event.data.frameName, event.backtest, new Date(event.data.timestamp));
|
|
48504
48540
|
};
|
|
48505
48541
|
/**
|
|
48506
48542
|
* Retrieves the latest persisted signal for the given context.
|
|
@@ -48637,7 +48673,7 @@ class RecentPersistLiveUtils {
|
|
|
48637
48673
|
backtest.loggerService.info(RECENT_PERSIST_LIVE_METHOD_NAME_HANDLE_ACTIVE_PING, {
|
|
48638
48674
|
signalId: event.data.id,
|
|
48639
48675
|
});
|
|
48640
|
-
await PersistRecentAdapter.writeRecentData(event.data, event.symbol, event.strategyName, event.exchangeName, event.data.frameName, event.backtest);
|
|
48676
|
+
await PersistRecentAdapter.writeRecentData(event.data, event.symbol, event.strategyName, event.exchangeName, event.data.frameName, event.backtest, new Date(event.data.timestamp));
|
|
48641
48677
|
};
|
|
48642
48678
|
/**
|
|
48643
48679
|
* Retrieves the latest persisted signal for the given context.
|
|
@@ -49292,7 +49328,7 @@ class StatePersistInstance {
|
|
|
49292
49328
|
}
|
|
49293
49329
|
this._when = when.getTime();
|
|
49294
49330
|
const id = CREATE_KEY_FN$6(this.signalId, this.bucketName);
|
|
49295
|
-
await PersistStateAdapter.writeStateData({ id, data: this._value, when: this._when }, this.signalId, this.bucketName);
|
|
49331
|
+
await PersistStateAdapter.writeStateData({ id, data: this._value, when: this._when }, this.signalId, this.bucketName, when);
|
|
49296
49332
|
return this._value;
|
|
49297
49333
|
});
|
|
49298
49334
|
}
|
|
@@ -50101,7 +50137,7 @@ class SessionPersistInstance {
|
|
|
50101
50137
|
this._data = value;
|
|
50102
50138
|
this._when = when.getTime();
|
|
50103
50139
|
const id = CREATE_KEY_FN$5(this.symbol, this.strategyName, this.exchangeName, this.frameName, this.backtest);
|
|
50104
|
-
await PersistSessionAdapter.writeSessionData({ id, data: value, when: this._when }, this.strategyName, this.exchangeName, this.frameName);
|
|
50140
|
+
await PersistSessionAdapter.writeSessionData({ id, data: value, when: this._when }, this.strategyName, this.exchangeName, this.frameName, when);
|
|
50105
50141
|
};
|
|
50106
50142
|
}
|
|
50107
50143
|
/** Releases resources held by this instance. */
|
|
@@ -50885,7 +50921,7 @@ class MemoryPersistInstance {
|
|
|
50885
50921
|
});
|
|
50886
50922
|
const priority = Date.now();
|
|
50887
50923
|
const whenMs = when.getTime();
|
|
50888
|
-
await PersistMemoryAdapter.writeMemoryData({ data: value, priority, removed: false, index, when: whenMs }, this.signalId, this.bucketName, memoryId);
|
|
50924
|
+
await PersistMemoryAdapter.writeMemoryData({ data: value, priority, removed: false, index, when: whenMs }, this.signalId, this.bucketName, memoryId, when);
|
|
50889
50925
|
this._index.upsert({
|
|
50890
50926
|
id: memoryId,
|
|
50891
50927
|
content: value,
|