backtest-kit 13.5.0 → 13.6.0
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 +403 -1
- package/build/index.mjs +403 -1
- package/package.json +1 -1
- package/types.d.ts +299 -2
package/build/index.cjs
CHANGED
|
@@ -649,6 +649,15 @@ const DEFAULT_CONFIG = Object.freeze({ ...GLOBAL_CONFIG });
|
|
|
649
649
|
* Consumers should implement retry logic in their listeners to handle transient synchronization failures.
|
|
650
650
|
*/
|
|
651
651
|
const syncSubject = new functoolsKit.Subject();
|
|
652
|
+
/**
|
|
653
|
+
* Pending-order synchronization emitter.
|
|
654
|
+
* Emitted on every live tick while a pending signal is monitored, BEFORE TP/SL/time evaluation.
|
|
655
|
+
* Asks the exchange whether the order is STILL pending (open).
|
|
656
|
+
*
|
|
657
|
+
* If a listener returns false OR throws, the order is treated as no longer open on the exchange
|
|
658
|
+
* and the framework closes the pending signal with closeReason "closed". Never emitted in backtest.
|
|
659
|
+
*/
|
|
660
|
+
const syncPendingSubject = new functoolsKit.Subject();
|
|
652
661
|
/**
|
|
653
662
|
* Global signal emitter for all trading events (live + backtest).
|
|
654
663
|
* Emits all signal events regardless of execution mode.
|
|
@@ -856,6 +865,7 @@ var emitters = /*#__PURE__*/Object.freeze({
|
|
|
856
865
|
signalLiveEmitter: signalLiveEmitter,
|
|
857
866
|
signalNotifySubject: signalNotifySubject,
|
|
858
867
|
strategyCommitSubject: strategyCommitSubject,
|
|
868
|
+
syncPendingSubject: syncPendingSubject,
|
|
859
869
|
syncSubject: syncSubject,
|
|
860
870
|
validationSubject: validationSubject,
|
|
861
871
|
walkerCompleteSubject: walkerCompleteSubject,
|
|
@@ -7075,6 +7085,64 @@ const CALL_SIGNAL_SYNC_CLOSE_FN = functoolsKit.trycatch(async (timestamp, curren
|
|
|
7075
7085
|
errorEmitter.next(error);
|
|
7076
7086
|
}
|
|
7077
7087
|
});
|
|
7088
|
+
/**
|
|
7089
|
+
* Calls onSignalPing callback for the pending-order synchronization event.
|
|
7090
|
+
*
|
|
7091
|
+
* Invoked at the start of the pending-signal monitoring block on every LIVE tick, BEFORE the
|
|
7092
|
+
* framework evaluates TP/SL/time completion. It asks the external order management system
|
|
7093
|
+
* whether the order backing this position is STILL pending (open) on the exchange.
|
|
7094
|
+
*
|
|
7095
|
+
* The Subject `await .next()` propagates listener exceptions passthrough, so the trycatch wrapper
|
|
7096
|
+
* collapses both a thrown listener and an explicit `false` into `false` (defaultValue). A `false`
|
|
7097
|
+
* result means the order is no longer open on the exchange and the caller closes the position with
|
|
7098
|
+
* closeReason "closed". A missing/true result keeps the position under normal TP/SL monitoring.
|
|
7099
|
+
*/
|
|
7100
|
+
const CALL_SIGNAL_PING_FN = functoolsKit.trycatch(async (timestamp, currentPrice, signal, self) => {
|
|
7101
|
+
const publicSignal = TO_PUBLIC_SIGNAL("pending", signal, currentPrice);
|
|
7102
|
+
return await self.params.onSignalPing({
|
|
7103
|
+
action: "signal-ping",
|
|
7104
|
+
symbol: self.params.execution.context.symbol,
|
|
7105
|
+
strategyName: self.params.strategyName,
|
|
7106
|
+
exchangeName: self.params.exchangeName,
|
|
7107
|
+
frameName: self.params.frameName,
|
|
7108
|
+
backtest: self.params.execution.context.backtest,
|
|
7109
|
+
signalId: signal.id,
|
|
7110
|
+
timestamp,
|
|
7111
|
+
signal: publicSignal,
|
|
7112
|
+
currentPrice,
|
|
7113
|
+
pnl: publicSignal.pnl,
|
|
7114
|
+
peakProfit: publicSignal.peakProfit,
|
|
7115
|
+
maxDrawdown: publicSignal.maxDrawdown,
|
|
7116
|
+
position: publicSignal.position,
|
|
7117
|
+
priceOpen: publicSignal.priceOpen,
|
|
7118
|
+
priceTakeProfit: publicSignal.priceTakeProfit,
|
|
7119
|
+
priceStopLoss: publicSignal.priceStopLoss,
|
|
7120
|
+
originalPriceTakeProfit: publicSignal.originalPriceTakeProfit,
|
|
7121
|
+
originalPriceStopLoss: publicSignal.originalPriceStopLoss,
|
|
7122
|
+
originalPriceOpen: publicSignal.originalPriceOpen,
|
|
7123
|
+
scheduledAt: publicSignal.scheduledAt,
|
|
7124
|
+
pendingAt: publicSignal.pendingAt,
|
|
7125
|
+
totalEntries: publicSignal.totalEntries,
|
|
7126
|
+
totalPartials: publicSignal.totalPartials,
|
|
7127
|
+
});
|
|
7128
|
+
}, {
|
|
7129
|
+
defaultValue: false,
|
|
7130
|
+
fallback: (error, timestamp, currentPrice, signal, self) => {
|
|
7131
|
+
const message = "ClientStrategy CALL_SIGNAL_PING_FN thrown";
|
|
7132
|
+
const payload = {
|
|
7133
|
+
error: functoolsKit.errorData(error),
|
|
7134
|
+
message: functoolsKit.getErrorMessage(error),
|
|
7135
|
+
data: {
|
|
7136
|
+
timestamp,
|
|
7137
|
+
currentPrice,
|
|
7138
|
+
signalId: signal.id,
|
|
7139
|
+
}
|
|
7140
|
+
};
|
|
7141
|
+
self.params.logger.warn(message, payload);
|
|
7142
|
+
console.warn(message, payload);
|
|
7143
|
+
errorEmitter.next(error);
|
|
7144
|
+
}
|
|
7145
|
+
});
|
|
7078
7146
|
/**
|
|
7079
7147
|
* Calls onCommit callback with strategy commit event.
|
|
7080
7148
|
*
|
|
@@ -8996,6 +9064,47 @@ const CLOSE_PENDING_SIGNAL_FN = async (self, signal, currentPrice, closeReason)
|
|
|
8996
9064
|
await CALL_TICK_CALLBACKS_FN(self, self.params.execution.context.symbol, result, currentTime, self.params.execution.context.backtest);
|
|
8997
9065
|
return result;
|
|
8998
9066
|
};
|
|
9067
|
+
/**
|
|
9068
|
+
* Closes the pending signal with closeReason "closed" after the pending-order ping reported the
|
|
9069
|
+
* order is no longer open on the exchange (CALL_SIGNAL_PING_FN returned false / threw).
|
|
9070
|
+
*
|
|
9071
|
+
* Unlike CLOSE_PENDING_SIGNAL_FN this does NOT re-confirm via onSignalSync — the ping already
|
|
9072
|
+
* established the order is gone, so re-asking the broker would be redundant. Runs the same teardown
|
|
9073
|
+
* (close callback, partial/breakeven clear, risk remove, setPendingSignal(null)). Live-only path.
|
|
9074
|
+
*/
|
|
9075
|
+
const CLOSE_PENDING_SIGNAL_AS_CLOSED_FN = async (self, signal, currentPrice) => {
|
|
9076
|
+
const currentTime = self.params.execution.context.when.getTime();
|
|
9077
|
+
const publicSignal = TO_PUBLIC_SIGNAL("pending", signal, currentPrice);
|
|
9078
|
+
self.params.logger.info("ClientStrategy signal closed by pending-order ping (order no longer open on exchange)", {
|
|
9079
|
+
symbol: self.params.execution.context.symbol,
|
|
9080
|
+
signalId: signal.id,
|
|
9081
|
+
priceClose: currentPrice,
|
|
9082
|
+
pnlPercentage: publicSignal.pnl.pnlPercentage,
|
|
9083
|
+
});
|
|
9084
|
+
await CALL_CLOSE_CALLBACKS_FN(self, self.params.execution.context.symbol, signal, currentPrice, currentTime, self.params.execution.context.backtest);
|
|
9085
|
+
// КРИТИЧНО: Очищаем состояние ClientPartial при закрытии позиции
|
|
9086
|
+
await CALL_PARTIAL_CLEAR_FN(self, self.params.execution.context.symbol, signal, currentPrice, currentTime, self.params.execution.context.backtest);
|
|
9087
|
+
// КРИТИЧНО: Очищаем состояние ClientBreakeven при закрытии позиции
|
|
9088
|
+
await CALL_BREAKEVEN_CLEAR_FN(self, self.params.execution.context.symbol, signal, currentPrice, currentTime, self.params.execution.context.backtest);
|
|
9089
|
+
await CALL_RISK_REMOVE_SIGNAL_FN(self, self.params.execution.context.symbol, currentTime, self.params.execution.context.backtest);
|
|
9090
|
+
await self.setPendingSignal(null, currentPrice);
|
|
9091
|
+
const result = {
|
|
9092
|
+
action: "closed",
|
|
9093
|
+
signal: publicSignal,
|
|
9094
|
+
currentPrice: currentPrice,
|
|
9095
|
+
closeReason: "closed",
|
|
9096
|
+
closeTimestamp: currentTime,
|
|
9097
|
+
pnl: publicSignal.pnl,
|
|
9098
|
+
strategyName: self.params.method.context.strategyName,
|
|
9099
|
+
exchangeName: self.params.method.context.exchangeName,
|
|
9100
|
+
frameName: self.params.method.context.frameName,
|
|
9101
|
+
symbol: self.params.execution.context.symbol,
|
|
9102
|
+
backtest: self.params.execution.context.backtest,
|
|
9103
|
+
createdAt: currentTime,
|
|
9104
|
+
};
|
|
9105
|
+
await CALL_TICK_CALLBACKS_FN(self, self.params.execution.context.symbol, result, currentTime, self.params.execution.context.backtest);
|
|
9106
|
+
return result;
|
|
9107
|
+
};
|
|
8999
9108
|
const RETURN_PENDING_SIGNAL_ACTIVE_FN = async (self, signal, currentPrice, backtest) => {
|
|
9000
9109
|
let percentTp = 0;
|
|
9001
9110
|
let percentSl = 0;
|
|
@@ -11033,6 +11142,16 @@ class ClientStrategy {
|
|
|
11033
11142
|
}
|
|
11034
11143
|
// Monitor pending signal
|
|
11035
11144
|
const averagePrice = await this.params.exchange.getAveragePrice(this.params.execution.context.symbol);
|
|
11145
|
+
// Pending-order ping: before evaluating TP/SL/time, confirm the order is STILL open on the
|
|
11146
|
+
// exchange. CALL_SIGNAL_PING_FN returns false when the listener returns false OR throws
|
|
11147
|
+
// (Subject .next passthrough), meaning the order is no longer pending — close with "closed".
|
|
11148
|
+
// Skipped in backtest: there is no live exchange to query.
|
|
11149
|
+
if (!this.params.execution.context.backtest) {
|
|
11150
|
+
const stillPending = await CALL_SIGNAL_PING_FN(currentTime, averagePrice, this._pendingSignal, this);
|
|
11151
|
+
if (!stillPending) {
|
|
11152
|
+
return await CLOSE_PENDING_SIGNAL_AS_CLOSED_FN(this, this._pendingSignal, averagePrice);
|
|
11153
|
+
}
|
|
11154
|
+
}
|
|
11036
11155
|
const closedResult = await CHECK_PENDING_SIGNAL_COMPLETION_FN(this, this._pendingSignal, averagePrice);
|
|
11037
11156
|
if (closedResult) {
|
|
11038
11157
|
return closedResult;
|
|
@@ -12881,6 +13000,32 @@ const CREATE_SYNC_FN = (self, strategyName, exchangeName, frameName, backtest) =
|
|
|
12881
13000
|
},
|
|
12882
13001
|
defaultValue: false,
|
|
12883
13002
|
});
|
|
13003
|
+
/**
|
|
13004
|
+
* If the syncPendingSubject listener or any registered action throws, it means the order backing the
|
|
13005
|
+
* open position is no longer pending on the exchange (filled/cancelled/liquidated externally).
|
|
13006
|
+
* The trycatch wrapper collapses a throw OR an explicit false into false, and ClientStrategy closes
|
|
13007
|
+
* the pending signal with closeReason "closed". Skipped in backtest — there is no live exchange.
|
|
13008
|
+
*/
|
|
13009
|
+
const CREATE_SYNC_PENDING_FN = (self, strategyName, exchangeName, frameName, backtest) => functoolsKit.trycatch(async (event) => {
|
|
13010
|
+
if (event.backtest) {
|
|
13011
|
+
return true;
|
|
13012
|
+
}
|
|
13013
|
+
await syncPendingSubject.next(event);
|
|
13014
|
+
await self.actionCoreService.orderPing(backtest, event, { strategyName, exchangeName, frameName });
|
|
13015
|
+
return true;
|
|
13016
|
+
}, {
|
|
13017
|
+
fallback: (error) => {
|
|
13018
|
+
const message = "StrategyConnectionService CREATE_SYNC_PENDING_FN thrown. Order no longer pending on exchange";
|
|
13019
|
+
const payload = {
|
|
13020
|
+
error: functoolsKit.errorData(error),
|
|
13021
|
+
message: functoolsKit.getErrorMessage(error),
|
|
13022
|
+
};
|
|
13023
|
+
self.loggerService.warn(message, payload);
|
|
13024
|
+
console.error(message, payload);
|
|
13025
|
+
errorEmitter.next(error);
|
|
13026
|
+
},
|
|
13027
|
+
defaultValue: false,
|
|
13028
|
+
});
|
|
12884
13029
|
/**
|
|
12885
13030
|
* Emits signal tick results with correct execution context timestamp.
|
|
12886
13031
|
* Wraps emitter calls in ExecutionContextService.runInContext to preserve
|
|
@@ -13317,6 +13462,7 @@ class StrategyConnectionService {
|
|
|
13317
13462
|
onDispose: CREATE_COMMIT_DISPOSE_FN(this),
|
|
13318
13463
|
onCommit: CREATE_COMMIT_FN(this),
|
|
13319
13464
|
onSignalSync: CREATE_SYNC_FN(this, strategyName, exchangeName, frameName, backtest),
|
|
13465
|
+
onSignalPing: CREATE_SYNC_PENDING_FN(this, strategyName, exchangeName, frameName, backtest),
|
|
13320
13466
|
onHighestProfit: CREATE_HIGHEST_PROFIT_FN(this, strategyName, exchangeName, frameName, backtest),
|
|
13321
13467
|
onMaxDrawdown: CREATE_MAX_DRAWDOWN_FN(this, strategyName, exchangeName, frameName, backtest),
|
|
13322
13468
|
});
|
|
@@ -16251,6 +16397,22 @@ class ActionProxy {
|
|
|
16251
16397
|
await this._target.signalSync(event);
|
|
16252
16398
|
}
|
|
16253
16399
|
}
|
|
16400
|
+
/**
|
|
16401
|
+
* Gate for the pending-order ping (order still open on exchange?).
|
|
16402
|
+
* NOT wrapped in trycatch — exceptions propagate to CREATE_SYNC_PENDING_FN.
|
|
16403
|
+
*
|
|
16404
|
+
* @param event - Pending-ping event with action "signal-ping"
|
|
16405
|
+
*/
|
|
16406
|
+
async orderPing(event) {
|
|
16407
|
+
if (this._target.orderPing) {
|
|
16408
|
+
console.error("Action::orderPing is unwanted cause exchange integration should be implemented in Broker.useBrokerAdapter as an infrastructure domain layer");
|
|
16409
|
+
console.error("If you need to check whether the order is still open on the exchange, please use Broker.useBrokerAdapter with onOrderPing");
|
|
16410
|
+
console.error("If Action::orderPing throws the framework will close the position with closeReason \"closed\"!");
|
|
16411
|
+
console.error("");
|
|
16412
|
+
console.error("You have been warned!");
|
|
16413
|
+
await this._target.orderPing(event);
|
|
16414
|
+
}
|
|
16415
|
+
}
|
|
16254
16416
|
/**
|
|
16255
16417
|
* Cleans up resources with error capture.
|
|
16256
16418
|
*
|
|
@@ -16470,6 +16632,15 @@ const CALL_SIGNAL_SYNC_CALLBACK_FN = async (self, event, strategyName, frameName
|
|
|
16470
16632
|
await self.params.callbacks.onSignalSync(event, self.params.actionName, strategyName, frameName, isBacktest);
|
|
16471
16633
|
}
|
|
16472
16634
|
};
|
|
16635
|
+
/**
|
|
16636
|
+
* Calls onOrderPing callback WITHOUT trycatch — exceptions must propagate
|
|
16637
|
+
* up to CREATE_SYNC_PENDING_FN in StrategyConnectionService (which returns false on error).
|
|
16638
|
+
*/
|
|
16639
|
+
const CALL_ORDER_PING_CALLBACK_FN = async (self, event, strategyName, frameName, isBacktest) => {
|
|
16640
|
+
if (self.params.callbacks?.onOrderPing) {
|
|
16641
|
+
await self.params.callbacks.onOrderPing(event, self.params.actionName, strategyName, frameName, isBacktest);
|
|
16642
|
+
}
|
|
16643
|
+
};
|
|
16473
16644
|
/** Wrapper to call onInit callback with error handling */
|
|
16474
16645
|
const CALL_INIT_CALLBACK_FN = functoolsKit.trycatch(async (self, strategyName, frameName, backtest) => {
|
|
16475
16646
|
if (self.params.callbacks?.onInit) {
|
|
@@ -16848,6 +17019,25 @@ class ClientAction {
|
|
|
16848
17019
|
await CALL_SIGNAL_SYNC_CALLBACK_FN(this, event, this.params.strategyName, this.params.frameName, event.backtest);
|
|
16849
17020
|
}
|
|
16850
17021
|
;
|
|
17022
|
+
/**
|
|
17023
|
+
* Gate for the pending-order ping (order still open on exchange?).
|
|
17024
|
+
* NOT wrapped in trycatch — exceptions propagate to CREATE_SYNC_PENDING_FN.
|
|
17025
|
+
*/
|
|
17026
|
+
async orderPing(event) {
|
|
17027
|
+
this.params.logger.debug("ClientAction orderPing", {
|
|
17028
|
+
actionName: this.params.actionName,
|
|
17029
|
+
strategyName: this.params.strategyName,
|
|
17030
|
+
frameName: this.params.frameName,
|
|
17031
|
+
});
|
|
17032
|
+
if (!this._handlerInstance) {
|
|
17033
|
+
await this.waitForInit();
|
|
17034
|
+
}
|
|
17035
|
+
// Call handler method if defined — exceptions propagate
|
|
17036
|
+
await this._handlerInstance?.orderPing(event);
|
|
17037
|
+
// Call callback if defined — exceptions propagate
|
|
17038
|
+
await CALL_ORDER_PING_CALLBACK_FN(this, event, this.params.strategyName, this.params.frameName, event.backtest);
|
|
17039
|
+
}
|
|
17040
|
+
;
|
|
16851
17041
|
}
|
|
16852
17042
|
|
|
16853
17043
|
/**
|
|
@@ -17110,6 +17300,22 @@ class ActionConnectionService {
|
|
|
17110
17300
|
const action = this.getAction(context.actionName, context.strategyName, context.exchangeName, context.frameName, backtest);
|
|
17111
17301
|
await action.signalSync(event);
|
|
17112
17302
|
};
|
|
17303
|
+
/**
|
|
17304
|
+
* Routes orderPing event to appropriate ClientAction instance.
|
|
17305
|
+
* NOT wrapped in trycatch — exceptions propagate to CREATE_SYNC_PENDING_FN.
|
|
17306
|
+
*
|
|
17307
|
+
* @param event - Pending-ping event with action "signal-ping"
|
|
17308
|
+
* @param backtest - Whether running in backtest mode
|
|
17309
|
+
* @param context - Execution context
|
|
17310
|
+
*/
|
|
17311
|
+
this.orderPing = async (event, backtest, context) => {
|
|
17312
|
+
this.loggerService.log("actionConnectionService orderPing", {
|
|
17313
|
+
backtest,
|
|
17314
|
+
context,
|
|
17315
|
+
});
|
|
17316
|
+
const action = this.getAction(context.actionName, context.strategyName, context.exchangeName, context.frameName, backtest);
|
|
17317
|
+
await action.orderPing(event);
|
|
17318
|
+
};
|
|
17113
17319
|
/**
|
|
17114
17320
|
* Disposes the ClientAction instance for the given action name.
|
|
17115
17321
|
*
|
|
@@ -19334,6 +19540,24 @@ class ActionCoreService {
|
|
|
19334
19540
|
await this.actionConnectionService.signalSync(event, backtest, { actionName, ...context });
|
|
19335
19541
|
}
|
|
19336
19542
|
};
|
|
19543
|
+
/**
|
|
19544
|
+
* Gates the pending-order ping across all registered actions.
|
|
19545
|
+
* NOT wrapped in trycatch — exceptions propagate to CREATE_SYNC_PENDING_FN.
|
|
19546
|
+
*
|
|
19547
|
+
* @param backtest - Whether running in backtest mode
|
|
19548
|
+
* @param event - Pending-ping event with action "signal-ping"
|
|
19549
|
+
* @param context - Strategy execution context
|
|
19550
|
+
*/
|
|
19551
|
+
this.orderPing = async (backtest, event, context) => {
|
|
19552
|
+
this.loggerService.log("actionCoreService orderPing", {
|
|
19553
|
+
context,
|
|
19554
|
+
});
|
|
19555
|
+
await this.validate(context);
|
|
19556
|
+
const { actions = [] } = this.strategySchemaService.get(context.strategyName);
|
|
19557
|
+
for (const actionName of actions) {
|
|
19558
|
+
await this.actionConnectionService.orderPing(event, backtest, { actionName, ...context });
|
|
19559
|
+
}
|
|
19560
|
+
};
|
|
19337
19561
|
/**
|
|
19338
19562
|
* Disposes all ClientAction instances for the strategy.
|
|
19339
19563
|
*
|
|
@@ -19802,6 +20026,29 @@ const VALID_METHOD_NAMES = [
|
|
|
19802
20026
|
"riskRejection",
|
|
19803
20027
|
"dispose",
|
|
19804
20028
|
];
|
|
20029
|
+
/**
|
|
20030
|
+
* Exchange-integration handler methods that exist on IAction but are intentionally NOT in
|
|
20031
|
+
* VALID_METHOD_NAMES. They are discouraged on action handlers: exchange synchronization belongs
|
|
20032
|
+
* in the infrastructure domain layer (Broker.useBrokerAdapter), not in actions. Naming a handler
|
|
20033
|
+
* method one of these produces a dedicated error redirecting to the Broker adapter instead of the
|
|
20034
|
+
* generic "invalid method" suggestion.
|
|
20035
|
+
*/
|
|
20036
|
+
const DISCOURAGED_METHOD_NAMES = ["signalSync", "orderPing"];
|
|
20037
|
+
/**
|
|
20038
|
+
* Builds the dedicated error message for a discouraged exchange-integration handler method.
|
|
20039
|
+
*
|
|
20040
|
+
* @param actionName - Name of the action being validated
|
|
20041
|
+
* @param methodName - The discouraged method name found on the handler
|
|
20042
|
+
* @returns Multi-line error message redirecting to the Broker adapter
|
|
20043
|
+
*/
|
|
20044
|
+
const DISCOURAGED_METHOD_MESSAGE = (actionName, methodName) => functoolsKit.str.newline([
|
|
20045
|
+
`ActionSchema ${actionName} contains discouraged method "${methodName}". `,
|
|
20046
|
+
`Exchange integration must be implemented in Broker.useBrokerAdapter as the infrastructure domain layer, not in an action handler.`,
|
|
20047
|
+
functoolsKit.typo.nbsp,
|
|
20048
|
+
`Use Broker.useBrokerAdapter with onOrderPing (order still open?) and onSignalOpenCommit / onSignalCloseCommit (order fill) instead.`,
|
|
20049
|
+
functoolsKit.typo.nbsp,
|
|
20050
|
+
`If you want to keep this property name use one of these patterns: _${methodName} or #${methodName}`,
|
|
20051
|
+
]);
|
|
19805
20052
|
/**
|
|
19806
20053
|
* Calculates the Levenshtein distance between two strings.
|
|
19807
20054
|
*
|
|
@@ -19904,6 +20151,13 @@ const VALIDATE_CLASS_METHODS = (actionName, handler, self) => {
|
|
|
19904
20151
|
}
|
|
19905
20152
|
const descriptor = Object.getOwnPropertyDescriptor(handler.prototype, methodName);
|
|
19906
20153
|
const isMethod = descriptor && typeof descriptor.value === "function";
|
|
20154
|
+
if (isMethod && DISCOURAGED_METHOD_NAMES.includes(methodName)) {
|
|
20155
|
+
const msg = DISCOURAGED_METHOD_MESSAGE(actionName, methodName);
|
|
20156
|
+
self.loggerService.log(`actionValidationService exception thrown`, {
|
|
20157
|
+
msg,
|
|
20158
|
+
});
|
|
20159
|
+
console.log(msg);
|
|
20160
|
+
}
|
|
19907
20161
|
if (isMethod && !VALID_METHOD_NAMES.includes(methodName)) {
|
|
19908
20162
|
const suggestions = FIND_SUGGESTIONS(methodName, VALID_METHOD_NAMES);
|
|
19909
20163
|
const lines = [
|
|
@@ -19943,6 +20197,14 @@ const VALIDATE_OBJECT_METHODS = (actionName, handler, self) => {
|
|
|
19943
20197
|
if (methodName.startsWith("_")) {
|
|
19944
20198
|
continue;
|
|
19945
20199
|
}
|
|
20200
|
+
if (typeof handler[methodName] === "function" &&
|
|
20201
|
+
DISCOURAGED_METHOD_NAMES.includes(methodName)) {
|
|
20202
|
+
const msg = DISCOURAGED_METHOD_MESSAGE(actionName, methodName);
|
|
20203
|
+
self.loggerService.log(`actionValidationService exception thrown`, {
|
|
20204
|
+
msg,
|
|
20205
|
+
});
|
|
20206
|
+
console.log(msg);
|
|
20207
|
+
}
|
|
19946
20208
|
if (typeof handler[methodName] === "function" &&
|
|
19947
20209
|
!VALID_METHOD_NAMES.includes(methodName)) {
|
|
19948
20210
|
const suggestions = FIND_SUGGESTIONS(methodName, VALID_METHOD_NAMES);
|
|
@@ -42161,6 +42423,7 @@ const breakevenNewTakeProfitPrice = (priceTakeProfit, trailingPriceTakeProfit) =
|
|
|
42161
42423
|
|
|
42162
42424
|
const BROKER_METHOD_NAME_COMMIT_SIGNAL_OPEN = "BrokerAdapter.commitSignalOpen";
|
|
42163
42425
|
const BROKER_METHOD_NAME_COMMIT_SIGNAL_CLOSE = "BrokerAdapter.commitSignalClose";
|
|
42426
|
+
const BROKER_METHOD_NAME_COMMIT_SIGNAL_PENDING = "BrokerAdapter.commitSignalPending";
|
|
42164
42427
|
const BROKER_METHOD_NAME_COMMIT_PARTIAL_PROFIT = "BrokerAdapter.commitPartialProfit";
|
|
42165
42428
|
const BROKER_METHOD_NAME_COMMIT_PARTIAL_LOSS = "BrokerAdapter.commitPartialLoss";
|
|
42166
42429
|
const BROKER_METHOD_NAME_COMMIT_TRAILING_STOP = "BrokerAdapter.commitTrailingStop";
|
|
@@ -42174,6 +42437,7 @@ const BROKER_METHOD_NAME_CLEAR = "BrokerAdapter.clear";
|
|
|
42174
42437
|
const BROKER_BASE_METHOD_NAME_WAIT_FOR_INIT = "BrokerBase.waitForInit";
|
|
42175
42438
|
const BROKER_BASE_METHOD_NAME_ON_SIGNAL_OPEN = "BrokerBase.onSignalOpenCommit";
|
|
42176
42439
|
const BROKER_BASE_METHOD_NAME_ON_SIGNAL_CLOSE = "BrokerBase.onSignalCloseCommit";
|
|
42440
|
+
const BROKER_BASE_METHOD_NAME_ON_SIGNAL_PENDING = "BrokerBase.onOrderPing";
|
|
42177
42441
|
const BROKER_BASE_METHOD_NAME_ON_PARTIAL_PROFIT = "BrokerBase.onPartialProfitCommit";
|
|
42178
42442
|
const BROKER_BASE_METHOD_NAME_ON_PARTIAL_LOSS = "BrokerBase.onPartialLossCommit";
|
|
42179
42443
|
const BROKER_BASE_METHOD_NAME_ON_TRAILING_STOP = "BrokerBase.onTrailingStopCommit";
|
|
@@ -42222,6 +42486,25 @@ class BrokerProxy {
|
|
|
42222
42486
|
}
|
|
42223
42487
|
throw new Error("BrokerProxy onSignalOpenCommit is not implemented");
|
|
42224
42488
|
}
|
|
42489
|
+
/**
|
|
42490
|
+
* Forwards a pending-order ping to the underlying adapter.
|
|
42491
|
+
*
|
|
42492
|
+
* If the adapter does not implement `onOrderPing`, the call is silently skipped
|
|
42493
|
+
* (the order is assumed still open). When implemented, exceptions propagate — a throw means
|
|
42494
|
+
* the order was NOT FOUND by `payload.signalId` and the framework closes the position with
|
|
42495
|
+
* closeReason "closed". The adapter must throw ONLY on a confirmed "order not found by id"
|
|
42496
|
+
* result and SWALLOW transient/network errors (return normally), otherwise a connectivity blip
|
|
42497
|
+
* would wrongly close an open position.
|
|
42498
|
+
*
|
|
42499
|
+
* @param payload - Pending ping details: symbol, signalId, position, prices, pnl, context, backtest flag.
|
|
42500
|
+
*/
|
|
42501
|
+
async onOrderPing(payload) {
|
|
42502
|
+
if (this._instance.onOrderPing) {
|
|
42503
|
+
await this.waitForInit();
|
|
42504
|
+
await this._instance.onOrderPing(payload);
|
|
42505
|
+
return;
|
|
42506
|
+
}
|
|
42507
|
+
}
|
|
42225
42508
|
/**
|
|
42226
42509
|
* Forwards a signal-close event to the underlying adapter.
|
|
42227
42510
|
* Throws if the adapter does not implement `onSignalCloseCommit`.
|
|
@@ -42451,6 +42734,32 @@ class BrokerAdapter {
|
|
|
42451
42734
|
await instance.onSignalCloseCommit(payload);
|
|
42452
42735
|
}
|
|
42453
42736
|
};
|
|
42737
|
+
/**
|
|
42738
|
+
* Forwards a pending-order ping to the registered broker adapter.
|
|
42739
|
+
*
|
|
42740
|
+
* Called automatically via syncPendingSubject when `enable()` is active, on every live tick
|
|
42741
|
+
* while a pending signal is monitored. Skipped silently in backtest mode or when no adapter is
|
|
42742
|
+
* registered. Exceptions are NOT swallowed: a throw from the adapter propagates up to
|
|
42743
|
+
* syncPendingSubject.next() → CREATE_SYNC_PENDING_FN, which closes the position with "closed".
|
|
42744
|
+
*
|
|
42745
|
+
* @param payload - Pending ping details: symbol, position, prices, pnl, context, backtest flag
|
|
42746
|
+
*/
|
|
42747
|
+
this.commitSignalPending = async (payload) => {
|
|
42748
|
+
bt.loggerService.info(BROKER_METHOD_NAME_COMMIT_SIGNAL_PENDING, {
|
|
42749
|
+
symbol: payload.symbol,
|
|
42750
|
+
context: payload.context,
|
|
42751
|
+
});
|
|
42752
|
+
if (!this.enable.hasValue()) {
|
|
42753
|
+
return;
|
|
42754
|
+
}
|
|
42755
|
+
if (payload.backtest) {
|
|
42756
|
+
return;
|
|
42757
|
+
}
|
|
42758
|
+
const instance = this.getInstance();
|
|
42759
|
+
if (instance) {
|
|
42760
|
+
await instance.onOrderPing(payload);
|
|
42761
|
+
}
|
|
42762
|
+
};
|
|
42454
42763
|
/**
|
|
42455
42764
|
* Intercepts a partial-profit close before DI-core mutation.
|
|
42456
42765
|
*
|
|
@@ -42753,6 +43062,7 @@ class BrokerAdapter {
|
|
|
42753
43062
|
position: event.signal.position,
|
|
42754
43063
|
cost: event.signal.cost,
|
|
42755
43064
|
symbol: event.symbol,
|
|
43065
|
+
signalId: event.signalId,
|
|
42756
43066
|
priceTakeProfit: event.signal.priceTakeProfit,
|
|
42757
43067
|
priceStopLoss: event.signal.priceStopLoss,
|
|
42758
43068
|
priceOpen: event.signal.priceOpen,
|
|
@@ -42776,6 +43086,7 @@ class BrokerAdapter {
|
|
|
42776
43086
|
currentPrice: event.currentPrice,
|
|
42777
43087
|
cost: event.signal.cost,
|
|
42778
43088
|
symbol: event.symbol,
|
|
43089
|
+
signalId: event.signalId,
|
|
42779
43090
|
pnl: event.signal.pnl,
|
|
42780
43091
|
priceOpen: event.signal.priceOpen,
|
|
42781
43092
|
peakProfit: event.signal.peakProfit,
|
|
@@ -42792,7 +43103,29 @@ class BrokerAdapter {
|
|
|
42792
43103
|
backtest: event.backtest,
|
|
42793
43104
|
});
|
|
42794
43105
|
});
|
|
42795
|
-
const
|
|
43106
|
+
const unSignalPending = syncPendingSubject.subscribe(async (event) => {
|
|
43107
|
+
await this.commitSignalPending({
|
|
43108
|
+
position: event.position,
|
|
43109
|
+
currentPrice: event.currentPrice,
|
|
43110
|
+
symbol: event.symbol,
|
|
43111
|
+
signalId: event.signalId,
|
|
43112
|
+
priceOpen: event.priceOpen,
|
|
43113
|
+
priceTakeProfit: event.priceTakeProfit,
|
|
43114
|
+
priceStopLoss: event.priceStopLoss,
|
|
43115
|
+
pnl: event.pnl,
|
|
43116
|
+
peakProfit: event.peakProfit,
|
|
43117
|
+
maxDrawdown: event.maxDrawdown,
|
|
43118
|
+
totalEntries: event.totalEntries,
|
|
43119
|
+
totalPartials: event.totalPartials,
|
|
43120
|
+
context: {
|
|
43121
|
+
strategyName: event.strategyName,
|
|
43122
|
+
exchangeName: event.exchangeName,
|
|
43123
|
+
frameName: event.frameName,
|
|
43124
|
+
},
|
|
43125
|
+
backtest: event.backtest,
|
|
43126
|
+
});
|
|
43127
|
+
});
|
|
43128
|
+
const disposeFn = functoolsKit.compose(() => unSignalOpen(), () => unSignalClose(), () => unSignalPending());
|
|
42796
43129
|
return () => {
|
|
42797
43130
|
this.enable.clear();
|
|
42798
43131
|
disposeFn();
|
|
@@ -42965,6 +43298,44 @@ class BrokerBase {
|
|
|
42965
43298
|
context: payload.context,
|
|
42966
43299
|
});
|
|
42967
43300
|
}
|
|
43301
|
+
/**
|
|
43302
|
+
* Called on every live tick while a pending signal is monitored, BEFORE TP/SL/time evaluation.
|
|
43303
|
+
*
|
|
43304
|
+
* Override to query the exchange for the order by `payload.signalId` and THROW ONLY when it is
|
|
43305
|
+
* definitively NOT FOUND by that id (filled, cancelled, or liquidated externally) — the framework
|
|
43306
|
+
* then closes the position with closeReason "closed". The default implementation logs and returns
|
|
43307
|
+
* normally, which keeps the position under normal TP/SL monitoring.
|
|
43308
|
+
*
|
|
43309
|
+
* CRITICAL: swallow transient/network errors (timeout, 5xx, rate limit, disconnect) — return
|
|
43310
|
+
* normally instead of throwing. A thrown network error would wrongly close an open position; only
|
|
43311
|
+
* a confirmed "order not found by id" response is a valid reason to throw.
|
|
43312
|
+
*
|
|
43313
|
+
* @param payload - Pending ping details: symbol, signalId, position, prices, pnl, context, backtest
|
|
43314
|
+
*
|
|
43315
|
+
* @example
|
|
43316
|
+
* ```typescript
|
|
43317
|
+
* async onOrderPing(payload: BrokerSignalPendingPayload) {
|
|
43318
|
+
* super.onOrderPing(payload); // Keep parent logging
|
|
43319
|
+
* let order: Order | null;
|
|
43320
|
+
* try {
|
|
43321
|
+
* order = await this.exchange.getOrderById(payload.signalId);
|
|
43322
|
+
* } catch (networkError) {
|
|
43323
|
+
* // Transient/network error — swallow and keep the position open, retry next tick
|
|
43324
|
+
* return;
|
|
43325
|
+
* }
|
|
43326
|
+
* if (!order) {
|
|
43327
|
+
* // Confirmed not found by id — close the position
|
|
43328
|
+
* throw new Error(`Order ${payload.signalId} not found on the exchange`);
|
|
43329
|
+
* }
|
|
43330
|
+
* }
|
|
43331
|
+
* ```
|
|
43332
|
+
*/
|
|
43333
|
+
async onOrderPing(payload) {
|
|
43334
|
+
bt.loggerService.info(BROKER_BASE_METHOD_NAME_ON_SIGNAL_PENDING, {
|
|
43335
|
+
symbol: payload.symbol,
|
|
43336
|
+
context: payload.context,
|
|
43337
|
+
});
|
|
43338
|
+
}
|
|
42968
43339
|
/**
|
|
42969
43340
|
* Called when a position is fully closed (SL/TP hit or manual close).
|
|
42970
43341
|
*
|
|
@@ -43363,6 +43734,7 @@ async function commitPartialProfit(symbol, percentToClose) {
|
|
|
43363
43734
|
}
|
|
43364
43735
|
await Broker.commitPartialProfit({
|
|
43365
43736
|
symbol,
|
|
43737
|
+
signalId: signalForProfit.id,
|
|
43366
43738
|
percentToClose,
|
|
43367
43739
|
cost: percentToCloseCost(percentToClose, investedCostForProfit),
|
|
43368
43740
|
currentPrice,
|
|
@@ -43428,6 +43800,7 @@ async function commitPartialLoss(symbol, percentToClose) {
|
|
|
43428
43800
|
}
|
|
43429
43801
|
await Broker.commitPartialLoss({
|
|
43430
43802
|
symbol,
|
|
43803
|
+
signalId: signalForLoss.id,
|
|
43431
43804
|
percentToClose,
|
|
43432
43805
|
cost: percentToCloseCost(percentToClose, investedCostForLoss),
|
|
43433
43806
|
currentPrice,
|
|
@@ -43509,6 +43882,7 @@ async function commitTrailingStop(symbol, percentShift, currentPrice) {
|
|
|
43509
43882
|
}
|
|
43510
43883
|
await Broker.commitTrailingStop({
|
|
43511
43884
|
symbol,
|
|
43885
|
+
signalId: signal.id,
|
|
43512
43886
|
percentShift,
|
|
43513
43887
|
currentPrice,
|
|
43514
43888
|
newStopLossPrice: slPercentShiftToPrice(percentShift, signal.priceStopLoss, effectivePriceOpen, signal.position),
|
|
@@ -43589,6 +43963,7 @@ async function commitTrailingTake(symbol, percentShift, currentPrice) {
|
|
|
43589
43963
|
}
|
|
43590
43964
|
await Broker.commitTrailingTake({
|
|
43591
43965
|
symbol,
|
|
43966
|
+
signalId: signal.id,
|
|
43592
43967
|
percentShift,
|
|
43593
43968
|
currentPrice,
|
|
43594
43969
|
newTakeProfitPrice: tpPercentShiftToPrice(percentShift, signal.priceTakeProfit, effectivePriceOpen, signal.position),
|
|
@@ -43640,6 +44015,7 @@ async function commitTrailingStopCost(symbol, newStopLossPrice) {
|
|
|
43640
44015
|
}
|
|
43641
44016
|
await Broker.commitTrailingStop({
|
|
43642
44017
|
symbol,
|
|
44018
|
+
signalId: signal.id,
|
|
43643
44019
|
percentShift,
|
|
43644
44020
|
currentPrice,
|
|
43645
44021
|
newStopLossPrice,
|
|
@@ -43691,6 +44067,7 @@ async function commitTrailingTakeCost(symbol, newTakeProfitPrice) {
|
|
|
43691
44067
|
}
|
|
43692
44068
|
await Broker.commitTrailingTake({
|
|
43693
44069
|
symbol,
|
|
44070
|
+
signalId: signal.id,
|
|
43694
44071
|
percentShift,
|
|
43695
44072
|
currentPrice,
|
|
43696
44073
|
newTakeProfitPrice,
|
|
@@ -43752,6 +44129,7 @@ async function commitBreakeven(symbol) {
|
|
|
43752
44129
|
}
|
|
43753
44130
|
await Broker.commitBreakeven({
|
|
43754
44131
|
symbol,
|
|
44132
|
+
signalId: signal.id,
|
|
43755
44133
|
currentPrice,
|
|
43756
44134
|
newStopLossPrice: breakevenNewStopLossPrice(effectivePriceOpen),
|
|
43757
44135
|
newTakeProfitPrice: breakevenNewTakeProfitPrice(signal.priceTakeProfit, signal._trailingPriceTakeProfit),
|
|
@@ -43842,6 +44220,7 @@ async function commitAverageBuy(symbol, cost = GLOBAL_CONFIG.CC_POSITION_ENTRY_C
|
|
|
43842
44220
|
}
|
|
43843
44221
|
await Broker.commitAverageBuy({
|
|
43844
44222
|
symbol,
|
|
44223
|
+
signalId: signalForAvgBuy.id,
|
|
43845
44224
|
currentPrice,
|
|
43846
44225
|
cost,
|
|
43847
44226
|
position: signalForAvgBuy.position,
|
|
@@ -44225,6 +44604,7 @@ async function commitPartialProfitCost(symbol, dollarAmount) {
|
|
|
44225
44604
|
}
|
|
44226
44605
|
await Broker.commitPartialProfit({
|
|
44227
44606
|
symbol,
|
|
44607
|
+
signalId: signalForProfitCost.id,
|
|
44228
44608
|
percentToClose,
|
|
44229
44609
|
cost: dollarAmount,
|
|
44230
44610
|
currentPrice,
|
|
@@ -44293,6 +44673,7 @@ async function commitPartialLossCost(symbol, dollarAmount) {
|
|
|
44293
44673
|
}
|
|
44294
44674
|
await Broker.commitPartialLoss({
|
|
44295
44675
|
symbol,
|
|
44676
|
+
signalId: signalForLossCost.id,
|
|
44296
44677
|
percentToClose,
|
|
44297
44678
|
cost: dollarAmount,
|
|
44298
44679
|
currentPrice,
|
|
@@ -48847,6 +49228,7 @@ class BacktestUtils {
|
|
|
48847
49228
|
}
|
|
48848
49229
|
await Broker.commitPartialProfit({
|
|
48849
49230
|
symbol,
|
|
49231
|
+
signalId: signalForProfit.id,
|
|
48850
49232
|
percentToClose,
|
|
48851
49233
|
cost: percentToCloseCost(percentToClose, investedCostForProfit),
|
|
48852
49234
|
currentPrice,
|
|
@@ -48918,6 +49300,7 @@ class BacktestUtils {
|
|
|
48918
49300
|
}
|
|
48919
49301
|
await Broker.commitPartialLoss({
|
|
48920
49302
|
symbol,
|
|
49303
|
+
signalId: signalForLoss.id,
|
|
48921
49304
|
percentToClose,
|
|
48922
49305
|
cost: percentToCloseCost(percentToClose, investedCostForLoss),
|
|
48923
49306
|
currentPrice,
|
|
@@ -48991,6 +49374,7 @@ class BacktestUtils {
|
|
|
48991
49374
|
}
|
|
48992
49375
|
await Broker.commitPartialProfit({
|
|
48993
49376
|
symbol,
|
|
49377
|
+
signalId: signalForProfitCost.id,
|
|
48994
49378
|
percentToClose,
|
|
48995
49379
|
cost: dollarAmount,
|
|
48996
49380
|
currentPrice,
|
|
@@ -49064,6 +49448,7 @@ class BacktestUtils {
|
|
|
49064
49448
|
}
|
|
49065
49449
|
await Broker.commitPartialLoss({
|
|
49066
49450
|
symbol,
|
|
49451
|
+
signalId: signalForLossCost.id,
|
|
49067
49452
|
percentToClose,
|
|
49068
49453
|
cost: dollarAmount,
|
|
49069
49454
|
currentPrice,
|
|
@@ -49150,6 +49535,7 @@ class BacktestUtils {
|
|
|
49150
49535
|
}
|
|
49151
49536
|
await Broker.commitTrailingStop({
|
|
49152
49537
|
symbol,
|
|
49538
|
+
signalId: signal.id,
|
|
49153
49539
|
percentShift,
|
|
49154
49540
|
currentPrice,
|
|
49155
49541
|
newStopLossPrice: slPercentShiftToPrice(percentShift, signal.priceStopLoss, effectivePriceOpen, signal.position),
|
|
@@ -49235,6 +49621,7 @@ class BacktestUtils {
|
|
|
49235
49621
|
}
|
|
49236
49622
|
await Broker.commitTrailingTake({
|
|
49237
49623
|
symbol,
|
|
49624
|
+
signalId: signal.id,
|
|
49238
49625
|
percentShift,
|
|
49239
49626
|
currentPrice,
|
|
49240
49627
|
newTakeProfitPrice: tpPercentShiftToPrice(percentShift, signal.priceTakeProfit, effectivePriceOpen, signal.position),
|
|
@@ -49289,6 +49676,7 @@ class BacktestUtils {
|
|
|
49289
49676
|
}
|
|
49290
49677
|
await Broker.commitTrailingStop({
|
|
49291
49678
|
symbol,
|
|
49679
|
+
signalId: signal.id,
|
|
49292
49680
|
percentShift,
|
|
49293
49681
|
currentPrice,
|
|
49294
49682
|
newStopLossPrice,
|
|
@@ -49343,6 +49731,7 @@ class BacktestUtils {
|
|
|
49343
49731
|
}
|
|
49344
49732
|
await Broker.commitTrailingTake({
|
|
49345
49733
|
symbol,
|
|
49734
|
+
signalId: signal.id,
|
|
49346
49735
|
percentShift,
|
|
49347
49736
|
currentPrice,
|
|
49348
49737
|
newTakeProfitPrice,
|
|
@@ -49404,6 +49793,7 @@ class BacktestUtils {
|
|
|
49404
49793
|
}
|
|
49405
49794
|
await Broker.commitBreakeven({
|
|
49406
49795
|
symbol,
|
|
49796
|
+
signalId: signal.id,
|
|
49407
49797
|
currentPrice,
|
|
49408
49798
|
newStopLossPrice: breakevenNewStopLossPrice(effectivePriceOpen),
|
|
49409
49799
|
newTakeProfitPrice: breakevenNewTakeProfitPrice(signal.priceTakeProfit, signal._trailingPriceTakeProfit),
|
|
@@ -49503,6 +49893,7 @@ class BacktestUtils {
|
|
|
49503
49893
|
}
|
|
49504
49894
|
await Broker.commitAverageBuy({
|
|
49505
49895
|
symbol,
|
|
49896
|
+
signalId: signalForAvgBuy.id,
|
|
49506
49897
|
currentPrice,
|
|
49507
49898
|
cost,
|
|
49508
49899
|
position: signalForAvgBuy.position,
|
|
@@ -51750,6 +52141,7 @@ class LiveUtils {
|
|
|
51750
52141
|
}
|
|
51751
52142
|
await Broker.commitPartialProfit({
|
|
51752
52143
|
symbol,
|
|
52144
|
+
signalId: signalForProfit.id,
|
|
51753
52145
|
percentToClose,
|
|
51754
52146
|
cost: percentToCloseCost(percentToClose, investedCost),
|
|
51755
52147
|
currentPrice,
|
|
@@ -51840,6 +52232,7 @@ class LiveUtils {
|
|
|
51840
52232
|
}
|
|
51841
52233
|
await Broker.commitPartialLoss({
|
|
51842
52234
|
symbol,
|
|
52235
|
+
signalId: signalForLoss.id,
|
|
51843
52236
|
percentToClose,
|
|
51844
52237
|
cost: percentToCloseCost(percentToClose, investedCost),
|
|
51845
52238
|
currentPrice,
|
|
@@ -51932,6 +52325,7 @@ class LiveUtils {
|
|
|
51932
52325
|
}
|
|
51933
52326
|
await Broker.commitPartialProfit({
|
|
51934
52327
|
symbol,
|
|
52328
|
+
signalId: signalForProfitCost.id,
|
|
51935
52329
|
percentToClose,
|
|
51936
52330
|
cost: dollarAmount,
|
|
51937
52331
|
currentPrice,
|
|
@@ -52024,6 +52418,7 @@ class LiveUtils {
|
|
|
52024
52418
|
}
|
|
52025
52419
|
await Broker.commitPartialLoss({
|
|
52026
52420
|
symbol,
|
|
52421
|
+
signalId: signalForLossCost.id,
|
|
52027
52422
|
percentToClose,
|
|
52028
52423
|
cost: dollarAmount,
|
|
52029
52424
|
currentPrice,
|
|
@@ -52129,6 +52524,7 @@ class LiveUtils {
|
|
|
52129
52524
|
}
|
|
52130
52525
|
await Broker.commitTrailingStop({
|
|
52131
52526
|
symbol,
|
|
52527
|
+
signalId: signal.id,
|
|
52132
52528
|
percentShift,
|
|
52133
52529
|
currentPrice,
|
|
52134
52530
|
newStopLossPrice: slPercentShiftToPrice(percentShift, signal.priceStopLoss, effectivePriceOpen, signal.position),
|
|
@@ -52229,6 +52625,7 @@ class LiveUtils {
|
|
|
52229
52625
|
}
|
|
52230
52626
|
await Broker.commitTrailingTake({
|
|
52231
52627
|
symbol,
|
|
52628
|
+
signalId: signal.id,
|
|
52232
52629
|
percentShift,
|
|
52233
52630
|
currentPrice,
|
|
52234
52631
|
newTakeProfitPrice: tpPercentShiftToPrice(percentShift, signal.priceTakeProfit, effectivePriceOpen, signal.position),
|
|
@@ -52299,6 +52696,7 @@ class LiveUtils {
|
|
|
52299
52696
|
}
|
|
52300
52697
|
await Broker.commitTrailingStop({
|
|
52301
52698
|
symbol,
|
|
52699
|
+
signalId: signal.id,
|
|
52302
52700
|
percentShift,
|
|
52303
52701
|
currentPrice,
|
|
52304
52702
|
newStopLossPrice,
|
|
@@ -52369,6 +52767,7 @@ class LiveUtils {
|
|
|
52369
52767
|
}
|
|
52370
52768
|
await Broker.commitTrailingTake({
|
|
52371
52769
|
symbol,
|
|
52770
|
+
signalId: signal.id,
|
|
52372
52771
|
percentShift,
|
|
52373
52772
|
currentPrice,
|
|
52374
52773
|
newTakeProfitPrice,
|
|
@@ -52446,6 +52845,7 @@ class LiveUtils {
|
|
|
52446
52845
|
}
|
|
52447
52846
|
await Broker.commitBreakeven({
|
|
52448
52847
|
symbol,
|
|
52848
|
+
signalId: signal.id,
|
|
52449
52849
|
currentPrice,
|
|
52450
52850
|
newStopLossPrice: breakevenNewStopLossPrice(effectivePriceOpen),
|
|
52451
52851
|
newTakeProfitPrice: breakevenNewTakeProfitPrice(signal.priceTakeProfit, signal._trailingPriceTakeProfit),
|
|
@@ -52563,6 +52963,7 @@ class LiveUtils {
|
|
|
52563
52963
|
}
|
|
52564
52964
|
await Broker.commitAverageBuy({
|
|
52565
52965
|
symbol,
|
|
52966
|
+
signalId: signalForAvgBuy.id,
|
|
52566
52967
|
currentPrice,
|
|
52567
52968
|
cost,
|
|
52568
52969
|
position: signalForAvgBuy.position,
|
|
@@ -59984,6 +60385,7 @@ const SUBJECT_ISOLATION_LIST = [
|
|
|
59984
60385
|
signalLiveEmitter,
|
|
59985
60386
|
strategyCommitSubject,
|
|
59986
60387
|
syncSubject,
|
|
60388
|
+
syncPendingSubject,
|
|
59987
60389
|
validationSubject,
|
|
59988
60390
|
signalNotifySubject,
|
|
59989
60391
|
beforeStartSubject,
|