@tradejs/strategies 1.0.6 → 1.0.8

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.
@@ -166,26 +166,28 @@ var buildVolumeDivergenceSetupFeatures = ({
166
166
 
167
167
  // src/VolumeDivergence/adapters/ai.ts
168
168
  var VOLUME_DIVERGENCE_CONTEXT_PROMPT = `
169
- \u0414\u043E\u043F\u043E\u043B\u043D\u0435\u043D\u0438\u0435 \u0434\u043B\u044F VolumeDivergence:
170
- - \u042D\u0442\u043E reversal-\u0441\u0435\u0442\u0430\u043F \u043D\u0430 \u0434\u0438\u0432\u0435\u0440\u0433\u0435\u043D\u0446\u0438\u0438 \u0446\u0435\u043D\u044B \u0438 \u043D\u043E\u0440\u043C\u0430\u043B\u0438\u0437\u043E\u0432\u0430\u043D\u043D\u043E\u0433\u043E \u043E\u0431\u044A\u0435\u043C\u0430, \u0430 \u043D\u0435 breakout-\u0441\u0442\u0440\u0430\u0442\u0435\u0433\u0438\u044F.
171
- - Bullish divergence: price \u0434\u0435\u043B\u0430\u0435\u0442 lower low, \u0430 volume \u0434\u0435\u043B\u0430\u0435\u0442 higher low.
172
- - Bearish divergence: price \u0434\u0435\u043B\u0430\u0435\u0442 higher high, \u0430 volume \u0434\u0435\u043B\u0430\u0435\u0442 lower high.
173
- - \u0414\u043B\u044F bullish-\u0441\u0438\u0433\u043D\u0430\u043B\u0430 \u043D\u0435 \u0437\u0430\u0432\u044B\u0448\u0430\u0439 quality, \u0435\u0441\u043B\u0438 \u0446\u0435\u043D\u0430 \u043F\u043E\u0441\u043B\u0435 pivot low \u0442\u0430\u043A \u0438 \u043D\u0435 \u0441\u043C\u043E\u0433\u043B\u0430 \u0437\u0430\u043C\u0435\u0442\u043D\u043E \u043E\u0442\u0441\u043A\u043E\u0447\u0438\u0442\u044C \u043E\u0442 \u0442\u0435\u043A\u0443\u0449\u0435\u0433\u043E pivot low \u0438\u043B\u0438 \u043D\u0435 \u0441\u043C\u043E\u0433\u043B\u0430 \u0432\u0435\u0440\u043D\u0443\u0442\u044C \u0445\u043E\u0442\u044F \u0431\u044B \u0447\u0430\u0441\u0442\u044C \u0441\u0442\u0440\u0443\u043A\u0442\u0443\u0440\u044B.
174
- - \u0414\u043B\u044F bearish-\u0441\u0438\u0433\u043D\u0430\u043B\u0430 \u0437\u0435\u0440\u043A\u0430\u043B\u044C\u043D\u043E: \u043D\u0435 \u0437\u0430\u0432\u044B\u0448\u0430\u0439 quality, \u0435\u0441\u043B\u0438 \u0446\u0435\u043D\u0430 \u043F\u043E\u0441\u043B\u0435 pivot high \u043D\u0435 \u0441\u043C\u043E\u0433\u043B\u0430 \u0437\u0430\u043C\u0435\u0442\u043D\u043E \u0443\u0439\u0442\u0438 \u0432\u043D\u0438\u0437 \u043E\u0442 \u0442\u0435\u043A\u0443\u0449\u0435\u0433\u043E pivot high.
175
- - \u0415\u0441\u043B\u0438 payload.additionalIndicators.volumeDivergenceContext.confirmationReady=false, \u043E\u0431\u044B\u0447\u043D\u043E \u044D\u0442\u043E \u0435\u0449\u0435 \u043D\u0435 fully confirmed reversal; \u0447\u0430\u0449\u0435 quality <= 4 \u0438 \u0447\u0430\u0441\u0442\u043E \u043D\u0443\u0436\u0435\u043D retest/confirmation.
176
- - \u0414\u043B\u044F live approve \u0441\u0447\u0438\u0442\u0430\u0439 confirmationReady \u043D\u0430\u043C\u043D\u043E\u0433\u043E \u0432\u0430\u0436\u043D\u0435\u0435, \u0447\u0435\u043C structureAdvanced: structure advance \u0441\u0430\u043C \u043F\u043E \u0441\u0435\u0431\u0435 \u0435\u0449\u0435 \u043D\u0435 \u043E\u0437\u043D\u0430\u0447\u0430\u0435\u0442 \u0433\u043E\u0442\u043E\u0432\u044B\u0439 reversal entry.
177
- - \u0414\u043B\u044F reversal-\u0441\u0435\u0442\u0430\u043F\u0430 \u043D\u0435 \u043D\u0430\u0433\u0440\u0430\u0436\u0434\u0430\u0439 quality \u0430\u0432\u0442\u043E\u043C\u0430\u0442\u0438\u0447\u0435\u0441\u043A\u0438 \u0442\u043E\u043B\u044C\u043A\u043E \u0437\u0430 \u0442\u043E, \u0447\u0442\u043E MA bias \u043F\u043E \u043C\u043E\u043D\u0435\u0442\u0435/BTC \u0443\u0436\u0435 \u0441\u043E\u0432\u043F\u0430\u0434\u0430\u0435\u0442 \u0441 \u043D\u0430\u043F\u0440\u0430\u0432\u043B\u0435\u043D\u0438\u0435\u043C \u0441\u0438\u0433\u043D\u0430\u043B\u0430.
178
- - \u0414\u043B\u044F LONG \u0441 entryTiming=structure_advance \u043E\u0431\u044B\u0447\u043D\u043E \u043D\u0435 \u0441\u0442\u0430\u0432\u044C quality=5: \u044D\u0442\u043E \u043F\u0440\u043E\u043C\u0435\u0436\u0443\u0442\u043E\u0447\u043D\u044B\u0439 \u044D\u0442\u0430\u043F, \u0430 \u043D\u0435 fully confirmed reversal.
179
- - \u0414\u043B\u044F SHORT \u0431\u0443\u0434\u044C \u0441\u0442\u0440\u043E\u0436\u0435, \u0447\u0435\u043C \u0434\u043B\u044F LONG: bearish reversal \u0434\u043E\u043B\u0436\u0435\u043D \u0442\u0440\u0435\u0431\u043E\u0432\u0430\u0442\u044C \u0431\u043E\u043B\u0435\u0435 \u0447\u0438\u0441\u0442\u043E\u0433\u043E follow-through, \u0430 \u043A\u043E\u043D\u0444\u043B\u0438\u043A\u0442 \u043F\u043E bias/delta \u0434\u043E\u043B\u0436\u0435\u043D \u0441\u0438\u043B\u044C\u043D\u0435\u0435 \u0441\u043D\u0438\u0436\u0430\u0442\u044C quality.
180
- - \u0415\u0441\u043B\u0438 deltaAtPivot \u043A\u043E\u043D\u0444\u043B\u0438\u043A\u0442\u0443\u0435\u0442 \u0441 \u043D\u0430\u043F\u0440\u0430\u0432\u043B\u0435\u043D\u0438\u0435\u043C reversal \u0438\u043B\u0438 bias \u043F\u043E \u043C\u043E\u043D\u0435\u0442\u0435/BTC \u043A\u043E\u043D\u0444\u043B\u0438\u043A\u0442\u0443\u0435\u0442 \u0441 \u0441\u0438\u0433\u043D\u0430\u043B\u043E\u043C, \u043D\u0435 \u0437\u0430\u0432\u044B\u0448\u0430\u0439 quality \u0442\u043E\u043B\u044C\u043A\u043E \u0438\u0437-\u0437\u0430 \u0441\u0430\u043C\u043E\u0439 \u0434\u0438\u0432\u0435\u0440\u0433\u0435\u043D\u0446\u0438\u0438.
181
- - \u0421\u043C\u043E\u0442\u0440\u0438 \u043D\u0430 divergenceAmplitudeAtrRatio / reclaimPct / confirmationCandleQuality: \u044D\u0442\u043E explicit setup-features, \u043E\u043F\u0438\u0441\u044B\u0432\u0430\u044E\u0449\u0438\u0435 \u043D\u0430\u0441\u043A\u043E\u043B\u044C\u043A\u043E \u0434\u0438\u0432\u0435\u0440\u0433\u0435\u043D\u0446\u0438\u044F \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043B\u044C\u043D\u043E \u0437\u043D\u0430\u0447\u0438\u043C\u0430 \u043E\u0442\u043D\u043E\u0441\u0438\u0442\u0435\u043B\u044C\u043D\u043E ATR, \u043D\u0430\u0441\u043A\u043E\u043B\u044C\u043A\u043E \u0446\u0435\u043D\u0430 \u0432\u0435\u0440\u043D\u0443\u043B\u0430 \u0441\u0442\u0440\u0443\u043A\u0442\u0443\u0440\u0443 \u0438 \u043D\u0430\u0441\u043A\u043E\u043B\u044C\u043A\u043E \u043A\u0430\u0447\u0435\u0441\u0442\u0432\u0435\u043D\u043D\u043E\u0439 \u0431\u044B\u043B\u0430 confirmation candle.
182
- - confirmationDistancePct \u043F\u043E\u043A\u0430\u0437\u044B\u0432\u0430\u0435\u0442, \u043D\u0430\u0441\u043A\u043E\u043B\u044C\u043A\u043E \u0434\u0430\u043B\u0435\u043A\u043E \u0446\u0435\u043D\u0430 \u0443\u0448\u043B\u0430 \u0437\u0430 confirmation level; \u043D\u0435 \u0437\u0430\u0432\u044B\u0448\u0430\u0439 quality, \u0435\u0441\u043B\u0438 confirmation \u0432\u0440\u043E\u0434\u0435 \u0431\u044B \u0435\u0441\u0442\u044C, \u043D\u043E \u0437\u0430\u043A\u0440\u0435\u043F\u043B\u0435\u043D\u0438\u0435 \u0437\u0430 \u0443\u0440\u043E\u0432\u043D\u0435\u043C \u043C\u0438\u043D\u0438\u043C\u0430\u043B\u044C\u043D\u043E\u0435.
183
- - additionalIndicators.deltaAtPivot \u2014 \u044D\u0442\u043E proxy net-volume \u043F\u043E \u0441\u0432\u0435\u0447\u0435 pivot, \u0430 \u043D\u0435 \u043D\u0430\u0441\u0442\u043E\u044F\u0449\u0438\u0439 lower-timeframe volume delta TradingView.
169
+ VolumeDivergence addon:
170
+ - This is a reversal setup built on price and normalized-volume divergence, not a breakout strategy.
171
+ - Bullish divergence means price makes a lower low while volume makes a higher low.
172
+ - Bearish divergence means price makes a higher high while volume makes a lower high.
173
+ - For a bullish signal, do not overstate quality if price still failed to bounce meaningfully away from the current pivot low or failed to reclaim enough structure.
174
+ - For a bearish signal, mirror that logic: do not overstate quality if price failed to move down meaningfully away from the current pivot high.
175
+ - If \`payload.additionalIndicators.volumeDivergenceContext.confirmationReady=false\`, this is usually not a fully confirmed reversal yet; quality is often \`<= 4\` and a retest or confirmation is often still needed.
176
+ - For live approval, treat \`confirmationReady\` as much more important than \`structureAdvanced\`; structure advance alone does not mean the reversal is entry-ready.
177
+ - For a reversal setup, do not automatically reward quality just because the coin or BTC MA bias already matches the signal direction.
178
+ - For LONG with \`entryTiming=structure_advance\`, avoid \`quality=5\`; that is an intermediate phase, not a fully confirmed reversal.
179
+ - Be stricter for SHORT than for LONG: a bearish reversal should require cleaner follow-through, and bias or delta conflict should reduce quality more aggressively.
180
+ - If \`deltaAtPivot\` conflicts with the reversal direction or the coin/BTC bias conflicts with the signal, do not overstate quality just because divergence exists.
181
+ - Use \`divergenceAmplitudeAtrRatio\`, \`reclaimPct\`, and \`confirmationCandleQuality\` as explicit setup features describing how meaningful the divergence is relative to ATR, how much structure price reclaimed, and how strong the confirmation candle was.
182
+ - \`confirmationDistancePct\` tells you how far price moved beyond the confirmation level; do not overstate quality when confirmation exists only marginally.
183
+ - \`additionalIndicators.deltaAtPivot\` is a proxy net-volume value on the pivot candle, not true lower-timeframe TradingView volume delta.
184
+ - If \`payload.additionalIndicators.derivativesContext\` exists, use Coinalyze-derived open interest, funding, and liquidations as positioning context: a liquidation flush can strengthen reversal odds, while crowded positioning against the trade or stale or missing data should not mechanically increase quality.
184
185
  `;
185
186
  var VOLUME_DIVERGENCE_PAYLOAD_PROMPT = `
186
- - \u0412 payload.additionalIndicators.volumeDivergenceContext \u043F\u0435\u0440\u0435\u0434\u0430\u0435\u0442\u0441\u044F \u043A\u0440\u0430\u0442\u043A\u0430\u044F \u0441\u0432\u043E\u0434\u043A\u0430 \u043F\u043E \u0441\u0438\u043B\u0435 \u0434\u0438\u0432\u0435\u0440\u0433\u0435\u043D\u0446\u0438\u0438:
187
+ - \`payload.additionalIndicators.volumeDivergenceContext\` contains a compact divergence-strength summary:
187
188
  divergenceKind / confirmationPrice / confirmationReady / structureAdvanced / reboundFromPivotPct / confirmationDistancePct / priceDisplacementPct / divergenceAmplitudeAtrRatio / reclaimPct / confirmationCandleQuality / volumeDivergenceStrength / deltaAligned / coinBiasAligned / btcBiasAligned / deterministicQuality / approvalAllowedNow / structuralHardBlockReasons / maxAllowedQuality.
188
- - \u0418\u0441\u043F\u043E\u043B\u044C\u0437\u0443\u0439 \u044D\u0442\u043E\u0442 context \u043A\u0430\u043A explicit strategy-specific summary, \u0430 \u043D\u0435 \u043F\u044B\u0442\u0430\u0439\u0441\u044F \u0437\u0430\u043D\u043E\u0432\u043E \u0432\u044B\u0432\u0435\u0441\u0442\u0438 \u0442\u043E \u0436\u0435 \u0441\u0430\u043C\u043E\u0435 \u0442\u043E\u043B\u044C\u043A\u043E \u043F\u043E \u043E\u0431\u0449\u0438\u043C \u0441\u0432\u0435\u0447\u0430\u043C.
189
+ - Use this context as the explicit strategy-specific summary instead of trying to derive the same conclusion again only from generic candles.
190
+ - If \`payload.additionalIndicators.derivativesContext\` exists, it is a Coinalyze-derived summary of derivatives state at signal time; \`stale\` or \`missing_derivatives\` means that Coinalyze context must not be used.
189
191
  `;
190
192
  var toFiniteNumberOrNull = (value) => {
191
193
  if (typeof value === "number" && Number.isFinite(value)) {
@@ -622,13 +624,13 @@ var clampQuality = (quality, maxAllowedQuality) => Math.max(1, Math.min(5, Math.
622
624
  var getHardBlockReasonText = (reason) => {
623
625
  switch (reason) {
624
626
  case "no_rebound_from_pivot":
625
- return "\u0446\u0435\u043D\u0430 \u043D\u0435 \u0441\u043C\u043E\u0433\u043B\u0430 \u0443\u0439\u0442\u0438 \u043E\u0442 pivot \u0432 \u0441\u0442\u043E\u0440\u043E\u043D\u0443 reversal";
627
+ return "price failed to move away from the pivot in the reversal direction";
626
628
  case "weak_divergence_amplitude":
627
- return "\u0434\u0438\u0432\u0435\u0440\u0433\u0435\u043D\u0446\u0438\u044F \u0441\u043B\u0438\u0448\u043A\u043E\u043C \u043C\u0430\u043B\u0435\u043D\u044C\u043A\u0430\u044F \u043E\u0442\u043D\u043E\u0441\u0438\u0442\u0435\u043B\u044C\u043D\u043E ATR";
629
+ return "divergence amplitude is too small relative to ATR";
628
630
  case "weak_reclaim":
629
- return "\u0446\u0435\u043D\u0430 \u0432\u0435\u0440\u043D\u0443\u043B\u0430 \u0441\u043B\u0438\u0448\u043A\u043E\u043C \u043C\u0430\u043B\u043E \u0441\u0442\u0440\u0443\u043A\u0442\u0443\u0440\u044B \u043F\u043E\u0441\u043B\u0435 pivot";
631
+ return "price reclaimed too little structure after the pivot";
630
632
  case "weak_confirmation_candle":
631
- return "confirmation candle \u0441\u043B\u0438\u0448\u043A\u043E\u043C \u0441\u043B\u0430\u0431\u0430\u044F";
633
+ return "confirmation candle is too weak";
632
634
  default:
633
635
  return reason;
634
636
  }
@@ -638,9 +640,9 @@ var buildGuardrailReason = (context) => {
638
640
  return `VolumeDivergence guardrail: ${context.hardBlockReasons.map(getHardBlockReasonText).join("; ")}.`;
639
641
  }
640
642
  if (!context.confirmationReady && context.entryTiming == null) {
641
- return "VolumeDivergence guardrail: reversal \u0443\u0436\u0435 \u0432\u0438\u0434\u0435\u043D, \u043D\u043E confirmation level \u0435\u0449\u0435 \u043D\u0435 \u043F\u0440\u043E\u0439\u0434\u0435\u043D.";
643
+ return "VolumeDivergence guardrail: reversal is visible, but the confirmation level has not been cleared yet.";
642
644
  }
643
- return "VolumeDivergence guardrail: quality \u043E\u0433\u0440\u0430\u043D\u0438\u0447\u0435\u043D \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u043D\u043E\u0441\u0442\u044C\u044E \u0438 \u0441\u0438\u043B\u043E\u0439 reversal away from pivot.";
645
+ return "VolumeDivergence guardrail: quality is limited by confirmation state and the strength of reversal away from the pivot.";
644
646
  };
645
647
  var postProcessAnalysis = ({
646
648
  signal,
@@ -668,8 +670,8 @@ var postProcessAnalysis = ({
668
670
  takeProfitPrice: null,
669
671
  stopLossPrice: null,
670
672
  qualityReason: analysis.qualityReason || buildGuardrailReason(context),
671
- triggerInvalidation: analysis.triggerInvalidation || (context.confirmationPrice != null ? `\u0416\u0434\u0430\u0442\u044C \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u0438\u0435 reversal \u043E\u0442\u043D\u043E\u0441\u0438\u0442\u0435\u043B\u044C\u043D\u043E \u0443\u0440\u043E\u0432\u043D\u044F ${context.confirmationPrice}.` : "\u0416\u0434\u0430\u0442\u044C \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u043D\u044B\u0439 reversal \u043F\u043E\u0441\u043B\u0435 pivot."),
672
- comment: analysis.comment || (context.hardBlockReasons.length > 0 ? `VolumeDivergence \u043E\u0442\u043A\u043B\u043E\u043D\u0435\u043D: ${context.hardBlockReasons.map(getHardBlockReasonText).join("; ")}.` : "VolumeDivergence \u043F\u043E\u043A\u0430 \u043E\u0441\u0442\u0430\u0435\u0442\u0441\u044F \u0432 \u0441\u0442\u0430\u0434\u0438\u0438 watch \u0434\u043E \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u0438\u044F reversal.")
673
+ triggerInvalidation: analysis.triggerInvalidation || (context.confirmationPrice != null ? `Wait for reversal confirmation relative to level ${context.confirmationPrice}.` : "Wait for a confirmed reversal after the pivot."),
674
+ comment: analysis.comment || (context.hardBlockReasons.length > 0 ? `VolumeDivergence rejected: ${context.hardBlockReasons.map(getHardBlockReasonText).join("; ")}.` : "VolumeDivergence remains in watch mode until the reversal is confirmed.")
673
675
  };
674
676
  }
675
677
  return {
@@ -697,7 +699,7 @@ ${VOLUME_DIVERGENCE_PAYLOAD_PROMPT}`,
697
699
  const context = getVolumeDivergenceContextFromPayload(payload, signal);
698
700
  return `
699
701
 
700
- \u0414\u043E\u043F. \u043A\u043E\u043D\u0442\u0435\u043A\u0441\u0442 VolumeDivergence:
702
+ Additional VolumeDivergence context:
701
703
  - divergenceKind=${context.divergenceKind ?? "n/a"}
702
704
  - confirmationPrice=${context.confirmationPrice ?? "n/a"}
703
705
  - confirmationReady=${context.confirmationReady}
@@ -724,15 +726,15 @@ ${VOLUME_DIVERGENCE_PAYLOAD_PROMPT}`,
724
726
  - maxAllowedQuality=${context.maxAllowedQuality}
725
727
  - hardBlockReasons=${context.hardBlockReasons.join(", ") || "none"}
726
728
 
727
- \u041F\u0440\u0430\u0432\u0438\u043B\u043E \u0438\u043D\u0442\u0435\u0440\u043F\u0440\u0435\u0442\u0430\u0446\u0438\u0438 \u0434\u043B\u044F VolumeDivergence:
728
- - \u0441\u043D\u0430\u0447\u0430\u043B\u0430 \u043E\u0446\u0435\u043D\u0438, \u0435\u0441\u0442\u044C \u043B\u0438 \u0440\u0435\u0430\u043B\u044C\u043D\u044B\u0439 reversal away from pivot, \u0430 \u043D\u0435 \u043F\u0440\u043E\u0441\u0442\u043E \u0444\u0430\u043A\u0442 \u0434\u0438\u0432\u0435\u0440\u0433\u0435\u043D\u0446\u0438\u0438;
729
- - confirmationReady=false \u043E\u0431\u044B\u0447\u043D\u043E \u043E\u0437\u043D\u0430\u0447\u0430\u0435\u0442, \u0447\u0442\u043E reversal \u0435\u0449\u0435 \u043D\u0435 fully confirmed;
730
- - \u0435\u0441\u043B\u0438 \u0446\u0435\u043D\u0430 \u043D\u0435 \u043E\u0442\u0441\u043A\u043E\u0447\u0438\u043B\u0430 \u043E\u0442 \u0442\u0435\u043A\u0443\u0449\u0435\u0433\u043E pivot \u0432 \u0441\u0442\u043E\u0440\u043E\u043D\u0443 \u0441\u0438\u0433\u043D\u0430\u043B\u0430, \u043D\u0435 \u0441\u0447\u0438\u0442\u0430\u0439 \u0441\u0435\u0442\u0430\u043F \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u043D\u044B\u043C;
731
- - conflict \u043F\u043E delta/bias \u0434\u043E\u043B\u0436\u0435\u043D \u0441\u043D\u0438\u0436\u0430\u0442\u044C quality, \u0430 \u043D\u0435 \u0438\u0433\u043D\u043E\u0440\u0438\u0440\u043E\u0432\u0430\u0442\u044C\u0441\u044F.
729
+ Interpretation rules for VolumeDivergence:
730
+ - first evaluate whether there is a real reversal away from the pivot, not just divergence on paper;
731
+ - \`confirmationReady=false\` usually means the reversal is not fully confirmed yet;
732
+ - if price did not bounce away from the current pivot in the signal direction, do not treat the setup as confirmed;
733
+ - delta or bias conflict should reduce quality, not be ignored.
732
734
  `;
733
735
  },
734
- mapEntryRuntimeFromConfig: (config) => mapAiRuntimeFromConfig(
735
- config
736
+ mapEntryRuntimeFromConfig: (config2) => mapAiRuntimeFromConfig(
737
+ config2
736
738
  )
737
739
  };
738
740
 
@@ -757,33 +759,78 @@ var volumeDivergenceMlAdapter = {
757
759
  normalizeStrategyConfig: (strategyConfig) => {
758
760
  return toVolumeDivergenceMlStrategyConfig(strategyConfig);
759
761
  },
760
- mapEntryRuntimeFromConfig: (config) => mapMlRuntimeFromConfig(config, {
762
+ mapEntryRuntimeFromConfig: (config2) => mapMlRuntimeFromConfig(config2, {
761
763
  strategyConfig: toVolumeDivergenceMlStrategyConfig(
762
- config
764
+ config2
763
765
  )
764
766
  })
765
767
  };
766
768
 
767
- // src/VolumeDivergence/hooks.ts
768
- import { createCloseOppositeBeforePlaceOrderHook } from "@tradejs/node/strategies";
769
- var volumeDivergenceBeforePlaceOrderHook = createCloseOppositeBeforePlaceOrderHook({
770
- isEnabled: (config) => Boolean(config.CLOSE_OPPOSITE_POSITIONS)
771
- });
772
-
773
769
  // src/VolumeDivergence/manifest.ts
774
770
  var volumeDivergenceManifest = {
775
771
  name: "VolumeDivergence",
776
- hooks: {
777
- beforePlaceOrder: volumeDivergenceBeforePlaceOrderHook
778
- },
779
772
  aiAdapter: volumeDivergenceAiAdapter,
780
773
  mlAdapter: volumeDivergenceMlAdapter
781
774
  };
782
775
 
776
+ // src/VolumeDivergence/config.ts
777
+ var config = {
778
+ ENV: "BACKTEST",
779
+ INTERVAL: "15",
780
+ MAKE_ORDERS: true,
781
+ CLOSE_OPPOSITE_POSITIONS: false,
782
+ BACKTEST_PRICE_MODE: "mid",
783
+ AI_ENABLED: false,
784
+ AI_MODE: "llm",
785
+ ML_ENABLED: false,
786
+ ML_THRESHOLD: 0.1,
787
+ MIN_AI_QUALITY: 3,
788
+ FEE_PERCENT: 5e-3,
789
+ MAX_LOSS_VALUE: 10,
790
+ MA_FAST: 14,
791
+ MA_MEDIUM: 49,
792
+ MA_SLOW: 50,
793
+ OBV_SMA: 10,
794
+ ATR: 14,
795
+ ATR_PCT_SHORT: 7,
796
+ ATR_PCT_LONG: 30,
797
+ BB: 20,
798
+ BB_STD: 2,
799
+ MACD_FAST: 12,
800
+ MACD_SLOW: 26,
801
+ MACD_SIGNAL: 9,
802
+ LEVEL_LOOKBACK: 20,
803
+ LEVEL_DELAY: 2,
804
+ NORMALIZATION_LENGTH: 100,
805
+ PIVOT_LOOKBACK_LEFT: 8,
806
+ PIVOT_LOOKBACK_RIGHT: 3,
807
+ MIN_BARS_BETWEEN_PIVOTS: 4,
808
+ MAX_BARS_BETWEEN_PIVOTS: 36,
809
+ ALLOW_STRUCTURE_ADVANCE_ENTRY: false,
810
+ MIN_DIVERGENCE_AMPLITUDE_ATR_RATIO: 0.35,
811
+ MIN_RECLAIM_PCT: 105,
812
+ MIN_CONFIRMATION_CANDLE_QUALITY: 0.58,
813
+ BULLISH: {
814
+ enable: true,
815
+ direction: "LONG",
816
+ TP: 4,
817
+ SL: 1.3,
818
+ minRiskRatio: 2
819
+ },
820
+ BEARISH: {
821
+ enable: true,
822
+ direction: "SHORT",
823
+ TP: 4,
824
+ SL: 1.3,
825
+ minRiskRatio: 2
826
+ }
827
+ };
828
+
783
829
  export {
784
830
  getVolumeDivergenceEntryThresholds,
785
831
  buildVolumeDivergenceSetupFeatures,
786
832
  volumeDivergenceAiAdapter,
787
833
  volumeDivergenceMlAdapter,
788
- volumeDivergenceManifest
834
+ volumeDivergenceManifest,
835
+ config
789
836
  };
@@ -0,0 +1,163 @@
1
+ // src/TrendShift/adapters/ai.ts
2
+ import { mapAiRuntimeFromConfig } from "@tradejs/core/strategies";
3
+ var getTrendShiftContext = (payload) => {
4
+ const additional = payload.additionalIndicators;
5
+ const raw = additional?.trendShiftContext ?? {};
6
+ const hardBlockReasons = [];
7
+ if (!raw.confirmedFlip) {
8
+ hardBlockReasons.push("unconfirmed_flip");
9
+ }
10
+ if (!raw.flipDistanceOk) {
11
+ hardBlockReasons.push("weak_flip_distance");
12
+ }
13
+ if (raw.coinBiasAligned === false) {
14
+ hardBlockReasons.push("coin_bias_conflict");
15
+ }
16
+ const slopeAbs = Math.abs(raw.avgSlopePct ?? 0);
17
+ const distanceAtrRatio = raw.distanceAtrRatio ?? 0;
18
+ const closeVsAvgPctAbs = Math.abs(raw.closeVsAvgPct ?? 0);
19
+ let deterministicQuality = 3;
20
+ if (hardBlockReasons.length > 0) {
21
+ deterministicQuality = raw.confirmedFlip ? 2 : 1;
22
+ } else if (distanceAtrRatio >= 0.8 && slopeAbs >= 0.09 && closeVsAvgPctAbs >= 0.12) {
23
+ deterministicQuality = 5;
24
+ } else if (distanceAtrRatio >= 0.45 && slopeAbs >= 0.04 && closeVsAvgPctAbs >= 0.05) {
25
+ deterministicQuality = 4;
26
+ }
27
+ return {
28
+ ...raw,
29
+ deterministicQuality,
30
+ approvalAllowedNow: deterministicQuality >= 4,
31
+ hardBlockReasons
32
+ };
33
+ };
34
+ var reasonText = (reason) => {
35
+ switch (reason) {
36
+ case "unconfirmed_flip":
37
+ return "the internal flip is not confirmed yet";
38
+ case "weak_flip_distance":
39
+ return "price moved away from the adaptive average too weakly";
40
+ case "coin_bias_conflict":
41
+ return "coin MA bias conflicts with the flip direction";
42
+ default:
43
+ return reason;
44
+ }
45
+ };
46
+ var trendShiftAiAdapter = {
47
+ buildPayload: ({ signal, basePayload }) => ({
48
+ ...basePayload,
49
+ additionalIndicators: {
50
+ ...basePayload.additionalIndicators,
51
+ trendShiftContext: signal.additionalIndicators?.trendShiftContext
52
+ }
53
+ }),
54
+ postProcessAnalysis: ({ payload, analysis }) => {
55
+ const context = getTrendShiftContext(payload);
56
+ const requestedDirection = analysis.direction === "LONG" || analysis.direction === "SHORT" ? analysis.direction : context.signalDirection;
57
+ if (context.approvalAllowedNow === true && requestedDirection != null) {
58
+ return {
59
+ ...analysis,
60
+ direction: requestedDirection,
61
+ quality: context.deterministicQuality,
62
+ approved: true
63
+ };
64
+ }
65
+ return {
66
+ ...analysis,
67
+ direction: null,
68
+ quality: context.deterministicQuality,
69
+ approved: false,
70
+ rejectReason: context.hardBlockReasons.length > 0 ? context.hardBlockReasons.map(reasonText).join("; ") : "the flip still does not look strong enough for live approval"
71
+ };
72
+ },
73
+ buildHumanPromptAddon: ({ payload }) => {
74
+ const context = getTrendShiftContext(payload);
75
+ return `
76
+ Additional TrendShift context:
77
+ - signalDirection=${context.signalDirection ?? "n/a"}
78
+ - confirmedFlip=${String(context.confirmedFlip)}
79
+ - bullFlip=${String(context.bullFlip)}
80
+ - bearFlip=${String(context.bearFlip)}
81
+ - flipDistanceOk=${String(context.flipDistanceOk)}
82
+ - closeVsAvgPct=${String(context.closeVsAvgPct ?? "n/a")}
83
+ - bandWidthPct=${String(context.bandWidthPct ?? "n/a")}
84
+ - avgSlopePct=${String(context.avgSlopePct ?? "n/a")}
85
+ - distanceAtrRatio=${String(context.distanceAtrRatio ?? "n/a")}
86
+ - coinBias=${context.coinBias ?? "n/a"}
87
+ - coinBiasAligned=${String(context.coinBiasAligned)}
88
+ - deterministicQuality=${context.deterministicQuality}
89
+ - approvalAllowedNow=${context.approvalAllowedNow}
90
+ - hardBlockReasons=${JSON.stringify(context.hardBlockReasons)}
91
+
92
+ Interpretation rules for TrendShift:
93
+ - This is a trend-state flip strategy, not a forecast of future impulse.
94
+ - If approvalAllowedNow=false, do not describe the signal as a fully confirmed live entry.
95
+ - If hardBlockReasons is not empty, explain exactly what is still missing for confirmation.
96
+ `.trim();
97
+ },
98
+ mapEntryRuntimeFromConfig: (config2) => mapAiRuntimeFromConfig(
99
+ config2
100
+ )
101
+ };
102
+
103
+ // src/TrendShift/manifest.ts
104
+ var trendShiftManifest = {
105
+ name: "TrendShift",
106
+ aiAdapter: trendShiftAiAdapter
107
+ };
108
+
109
+ // src/TrendShift/config.ts
110
+ var config = {
111
+ ENV: "BACKTEST",
112
+ INTERVAL: "15",
113
+ MAKE_ORDERS: true,
114
+ CLOSE_OPPOSITE_POSITIONS: false,
115
+ BACKTEST_PRICE_MODE: "mid",
116
+ AI_ENABLED: false,
117
+ AI_MODE: "llm",
118
+ ML_ENABLED: false,
119
+ ML_THRESHOLD: 0.1,
120
+ MIN_AI_QUALITY: 3,
121
+ FEE_PERCENT: 5e-3,
122
+ MAX_LOSS_VALUE: 10,
123
+ MA_FAST: 14,
124
+ MA_MEDIUM: 49,
125
+ MA_SLOW: 50,
126
+ OBV_SMA: 10,
127
+ ATR: 14,
128
+ ATR_PCT_SHORT: 7,
129
+ ATR_PCT_LONG: 30,
130
+ BB: 20,
131
+ BB_STD: 2,
132
+ MACD_FAST: 12,
133
+ MACD_SLOW: 26,
134
+ MACD_SIGNAL: 9,
135
+ TRENDSHIFT_MULTIPLICATIVE_FACTOR: 4,
136
+ TRENDSHIFT_SLOPE: 12,
137
+ TRENDSHIFT_ATR_LENGTH: 150,
138
+ TRENDSHIFT_WIDTH_PCT: 75,
139
+ TRENDSHIFT_CONFIRM_FLIP_WITH_CLOSE: true,
140
+ TRENDSHIFT_MIN_FLIP_DISTANCE_ATR: 0.15,
141
+ TRENDSHIFT_EXIT_ON_OPPOSITE_FLIP: true,
142
+ TRENDSHIFT_MAX_FIGURE_POINTS: 180,
143
+ LONG: {
144
+ enable: true,
145
+ direction: "LONG",
146
+ TP: 2.8,
147
+ SL: 1.1,
148
+ minRiskRatio: 1.6
149
+ },
150
+ SHORT: {
151
+ enable: true,
152
+ direction: "SHORT",
153
+ TP: 2.8,
154
+ SL: 1.1,
155
+ minRiskRatio: 1.6
156
+ }
157
+ };
158
+
159
+ export {
160
+ trendShiftAiAdapter,
161
+ trendShiftManifest,
162
+ config
163
+ };