@adaptic/utils 0.0.986 → 0.0.987

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -68029,9 +68029,15 @@ const RiskBudgetPrefsObjectSchema = objectType({
68029
68029
  maxCorrelatedExposurePct: numberType().min(0).max(100).default(40),
68030
68030
  betaTarget: numberType().nullable().default(null),
68031
68031
  maxBeta: numberType().min(0).default(2),
68032
- maxRiskPerTradePct: numberType().min(0).max(100).default(2),
68033
- maxLossPerDayPct: numberType().min(0).max(100).default(5),
68034
- maxLossPerWeekPct: numberType().min(0).max(100).default(10),
68032
+ // Tighter per-trade risk (1.5% vs 2%) for scalping — high turnover means
68033
+ // many small risks compound; per-trade ceiling must be lower than the
68034
+ // swing default to keep daily VAR bounded.
68035
+ maxRiskPerTradePct: numberType().min(0).max(100).default(1.5),
68036
+ // 2% daily loss circuit breaker (vs 5%) — tighter to fail fast when the
68037
+ // regime turns against the scalping strategy.
68038
+ maxLossPerDayPct: numberType().min(0).max(100).default(2.0),
68039
+ // 5% weekly loss cap (vs 10%) — proportional to the daily reduction.
68040
+ maxLossPerWeekPct: numberType().min(0).max(100).default(5.0),
68035
68041
  maxLossPerMonthPct: numberType().min(0).max(100).default(15),
68036
68042
  maxDrawdownFromPeakPct: numberType().min(0).max(100).default(20),
68037
68043
  maxSimultaneousSignalsPerStrategy: numberType().min(0).default(5),
@@ -68040,8 +68046,12 @@ const RiskBudgetPrefsObjectSchema = objectType({
68040
68046
  weekendExposureCapPct: numberType().min(0).max(100).default(30),
68041
68047
  eventRiskExposureCapPct: numberType().min(0).max(100).default(40),
68042
68048
  gapRiskSensitivity: enumType(["low", "medium", "high"]).default("medium"),
68043
- /** Per-trade equity allocation as % of account equity. Replaces legacy AlpacaAccount.tradeAllocationPct. */
68044
- perTradeAllocationPct: numberType().min(0).max(100).default(5),
68049
+ /**
68050
+ * Per-trade equity allocation as % of account equity. Replaces legacy AlpacaAccount.tradeAllocationPct.
68051
+ * Smaller per-trade size (2% vs 5%) for scalping — shorter holds + higher
68052
+ * concurrency demand smaller per-position bets.
68053
+ */
68054
+ perTradeAllocationPct: numberType().min(0).max(100).default(2),
68045
68055
  /** Per-trade crypto allocation as % of account equity. Replaces legacy AlpacaAccount.cryptoTradeAllocationPct. */
68046
68056
  perTradeCryptoAllocationPct: numberType().min(0).max(100).default(5),
68047
68057
  /** Alpaca day-trading buying power check enforcement. Synced to Alpaca API. */
@@ -68077,17 +68087,30 @@ const StrategyPriorityRuleSchema = objectType({
68077
68087
  const SignalConsumptionPrefsObjectSchema = objectType({
68078
68088
  enabledStrategies: arrayType(stringType()).default([]),
68079
68089
  disabledStrategies: arrayType(stringType()).default([]),
68080
- minConfidenceByDefault: numberType().min(0).max(100).default(60),
68090
+ // Slightly higher confidence floor (65 vs 60) reflecting the precision
68091
+ // demands of scalping — false positives compound rapidly at this cadence.
68092
+ minConfidenceByDefault: numberType().min(0).max(100).default(65),
68081
68093
  minConfidenceByAssetClass: recordType(stringType(), numberType()).default({}),
68082
68094
  minConfidenceByStrategy: recordType(stringType(), numberType()).default({}),
68083
- minExpectedRewardRiskRatio: numberType().min(0).default(1.5),
68095
+ // 1.3 R:R minimum — slightly tighter than the swing default (1.5) since
68096
+ // scalp trades have quicker resolution and tolerate marginally lower
68097
+ // expected R:R when win-rate is high.
68098
+ minExpectedRewardRiskRatio: numberType().min(0).default(1.3),
68084
68099
  minExpectedEdgePct: numberType().min(0).default(0),
68085
- maxSignalAgeSeconds: numberType().min(0).default(300),
68086
- cooldownAfterEntrySeconds: numberType().min(0).default(60),
68100
+ // 30s max signal age for scalping — anything older than that has likely
68101
+ // been re-priced out of edge. Previous default (300s) was swing-suitable.
68102
+ maxSignalAgeSeconds: numberType().min(0).default(30),
68103
+ // 5s post-entry cooldown — minimum churn protection while still allowing
68104
+ // rapid re-engagement if the setup persists.
68105
+ cooldownAfterEntrySeconds: numberType().min(0).default(5),
68087
68106
  cooldownAfterExitSeconds: numberType().min(0).default(120),
68088
- cooldownAfterStopOutSeconds: numberType().min(0).default(300),
68107
+ // 30s post-stop-out cooldown (vs 300s) — fast re-entry allowed once the
68108
+ // setup re-presents.
68109
+ cooldownAfterStopOutSeconds: numberType().min(0).default(30),
68089
68110
  cooldownAfterFailedTradeSeconds: numberType().min(0).default(180),
68090
- duplicateSignalSuppressionWindowSeconds: numberType().min(0).default(300),
68111
+ // 10s duplicate-signal window — prevents same-second signal dedup but
68112
+ // allows the same setup to trigger again within a minute.
68113
+ duplicateSignalSuppressionWindowSeconds: numberType().min(0).default(10),
68091
68114
  reversalHandlingPolicy: enumType([
68092
68115
  "ignore_reversal",
68093
68116
  "close_only",
@@ -68110,10 +68133,18 @@ const SignalConsumptionPrefsObjectSchema = objectType({
68110
68133
  earningsBlackoutEnabled: booleanType().default(false),
68111
68134
  earningsBlackoutHoursBefore: numberType().min(0).default(24),
68112
68135
  earningsBlackoutHoursAfter: numberType().min(0).default(2),
68113
- /** Minimum price movement % to qualify as a tradeable signal. Replaces legacy AlpacaAccount.minPercentageChange. */
68114
- minPercentageChange: numberType().min(0).default(0.5),
68115
- /** Minimum average daily volume to qualify a symbol for trading. Replaces legacy AlpacaAccount.volumeThreshold. */
68116
- volumeThreshold: numberType().min(0).default(50000),
68136
+ /**
68137
+ * Minimum price movement % to qualify as a tradeable signal. Replaces legacy AlpacaAccount.minPercentageChange.
68138
+ * Tighter intraday move filter (15bps vs 50bps) scalping captures
68139
+ * sub-percent moves that the swing-trading default would have ignored.
68140
+ */
68141
+ minPercentageChange: numberType().min(0).default(0.15),
68142
+ /**
68143
+ * Minimum average daily volume to qualify a symbol for trading. Replaces legacy AlpacaAccount.volumeThreshold.
68144
+ * Higher floor (100k vs 50k) — scalping requires consistent liquidity to
68145
+ * keep slippage within the tightened maxSlippageTolerancePct (0.3%).
68146
+ */
68147
+ volumeThreshold: numberType().min(0).default(100000),
68117
68148
  });
68118
68149
  const SignalConsumptionPrefsSchema = SignalConsumptionPrefsObjectSchema.default({});
68119
68150
 
@@ -68138,12 +68169,21 @@ const ExecutionPrefsObjectSchema = objectType({
68138
68169
  preferredOrderType: OrderTypeEnum.default("limit"),
68139
68170
  preferredOrderTypeByAssetClass: recordType(stringType(), stringType())
68140
68171
  .default({ crypto: "market" }),
68141
- defaultTimeInForce: enumType(["day", "gtc", "ioc", "fok"]).default("day"),
68172
+ // IOC default (immediate-or-cancel) for scalping — orders that don't
68173
+ // fill instantly should be killed, not parked on the book where they
68174
+ // accumulate stale-price risk.
68175
+ defaultTimeInForce: enumType(["day", "gtc", "ioc", "fok"]).default("ioc"),
68176
+ // Passive bias — scalping captures spread by posting on the book rather
68177
+ // than paying it. Aggressive crossings are reserved for risk-off / unwind.
68142
68178
  executionBias: enumType(["passive", "neutral", "aggressive"])
68143
- .default("neutral"),
68144
- maxSlippageTolerancePct: numberType().min(0).max(100).default(1.0),
68179
+ .default("passive"),
68180
+ // 30bps slippage tolerance (vs 100bps) — must be tighter than scalping
68181
+ // edge magnitudes (typically ~50-100bps) to preserve PnL.
68182
+ maxSlippageTolerancePct: numberType().min(0).max(100).default(0.3),
68145
68183
  priceCollarEnabled: booleanType().default(true),
68146
- priceCollarPct: numberType().min(0).default(2),
68184
+ // 50bps price collar (vs 200bps) — same logic as slippage tolerance:
68185
+ // collar must sit inside the edge magnitude.
68186
+ priceCollarPct: numberType().min(0).default(0.5),
68147
68187
  repriceEnabled: booleanType().default(false),
68148
68188
  repriceMaxAttempts: numberType().min(0).default(3),
68149
68189
  repriceIntervalSeconds: numberType().min(0).default(30),
@@ -68175,20 +68215,31 @@ const TrailingStopTighteningRuleSchema = objectType({
68175
68215
  const PositionManagementPrefsObjectSchema = objectType({
68176
68216
  defaultStopLossMethod: enumType(["fixed_percent", "atr_based", "structure_based", "trailing_stop"])
68177
68217
  .default("trailing_stop"),
68178
- defaultStopLossPct: numberType().min(0).max(100).default(4),
68179
- atrStopMultiplier: numberType().min(0).default(2),
68218
+ // 50bps stop sized for 5-min bar scalp profiles (audit 2026-05-10).
68219
+ defaultStopLossPct: numberType().min(0).max(100).default(0.5),
68220
+ // 0.75x ATR multiplier — tighter than the previous 2x to keep ATR-based
68221
+ // stops aligned with sub-percent intraday move ranges.
68222
+ atrStopMultiplier: numberType().min(0).default(0.75),
68180
68223
  defaultTakeProfitMethod: enumType(["fixed_percent", "atr_based", "risk_reward_ratio", "none"])
68181
68224
  .default("risk_reward_ratio"),
68182
- defaultTakeProfitPct: numberType().min(0).max(100).default(3),
68183
- defaultRiskRewardRatio: numberType().min(0).default(2),
68225
+ // 100bps take-profit pairs with the 50bps stop at a 2:1 R:R via the
68226
+ // explicit defaultRiskRewardRatio below; both serve different code paths
68227
+ // (fixed-percent vs ratio-derived TP).
68228
+ defaultTakeProfitPct: numberType().min(0).max(100).default(1.0),
68229
+ defaultRiskRewardRatio: numberType().min(0).default(1.5),
68184
68230
  breakEvenStopEnabled: booleanType().default(true),
68185
- breakEvenTriggerPct: numberType().min(0).max(100).default(2),
68231
+ // Move stop to break-even after 1% of profit (vs 2%) — tighter to match
68232
+ // scalping cadence.
68233
+ breakEvenTriggerPct: numberType().min(0).max(100).default(1),
68186
68234
  scaleInEnabled: booleanType().default(false),
68187
68235
  scaleInMaxAdds: numberType().min(0).default(2),
68188
68236
  scaleOutEnabled: booleanType().default(true),
68189
68237
  scaleOutTrimPct: numberType().min(0).max(100).default(50),
68190
- scaleOutTriggerPct: numberType().min(0).max(100).default(5),
68191
- maxHoldingPeriodMinutes: numberType().min(0).default(0),
68238
+ // Trim 50% at +0.5% — much earlier than the previous 5% for scalping.
68239
+ scaleOutTriggerPct: numberType().min(0).max(100).default(0.5),
68240
+ // Hard 30-min intraday hold cap. Previous default of 0 (unlimited) is
68241
+ // wrong for scalping where stale positions accumulate undefined risk.
68242
+ maxHoldingPeriodMinutes: numberType().min(0).default(30),
68192
68243
  maxHoldingPeriodByAssetClass: recordType(stringType(), numberType()).default({}),
68193
68244
  dayTradeOnly: booleanType().default(false),
68194
68245
  autoCloseBeforeEarnings: booleanType().default(false),
@@ -68206,7 +68257,9 @@ const PositionManagementPrefsObjectSchema = objectType({
68206
68257
  { profitThresholdPct: 10, newTrailPct: 1.0 },
68207
68258
  ]),
68208
68259
  portfolioStopOverridesPositionStops: booleanType().default(false),
68209
- doNotReenterAfterStopOutMinutes: numberType().min(0).default(30),
68260
+ // 10-min stop-out cooldown (vs 30) — fast re-entry permitted once the
68261
+ // adverse regime resolves.
68262
+ doNotReenterAfterStopOutMinutes: numberType().min(0).default(10),
68210
68263
  doNotReenterAfterForcedCloseMinutes: numberType().min(0).default(60),
68211
68264
  });
68212
68265
  const PositionManagementPrefsSchema = PositionManagementPrefsObjectSchema.default({});
@@ -68511,9 +68564,14 @@ const EffectiveTradingPolicySchema = objectType({
68511
68564
  });
68512
68565
 
68513
68566
  /**
68514
- * Conservative default trading policy used as the baseline when no
68515
- * user-customized policy exists. All nested preference sub-objects are
68516
- * passed as empty objects so Zod applies their field-level defaults.
68567
+ * Default trading policy used as the baseline when no user-customized policy
68568
+ * exists. Calibrated for short-horizon day trading / HFT-microstructuring /
68569
+ * scalping (intraday holds, 5-min-bar-sized stops, fast cooldowns) per the
68570
+ * 2026-05-10 audit, replacing the previous swing-trading calibration.
68571
+ *
68572
+ * All nested preference sub-objects are passed as empty objects so Zod applies
68573
+ * their field-level defaults (which are themselves tuned for scalping in their
68574
+ * respective schema files).
68517
68575
  *
68518
68576
  * Key choices:
68519
68577
  * - Advisory-only autonomy (no autonomous execution)
@@ -68522,6 +68580,14 @@ const EffectiveTradingPolicySchema = objectType({
68522
68580
  * - No shorting or margin (user must opt-in)
68523
68581
  * - All protective overlays disabled (user must opt-in)
68524
68582
  * - No LLM providers pre-configured
68583
+ * - Tighter per-trade allocation (2% vs 5%) and concurrency (8 positions vs 20)
68584
+ * reflecting the increased turnover and decreased per-position conviction
68585
+ * characteristic of scalping
68586
+ * - Faster equity wash-trade cooldown (5s vs 30s) — FINRA Rule 5210 governs
68587
+ * opposing-side wash trades; same-side intraday re-entry can be much faster
68588
+ * - Tighter daily-loss circuit breaker (2% vs 3%) reflecting that scalping
68589
+ * strategies should fail fast rather than burn the day's risk budget on
68590
+ * one bad regime
68525
68591
  */
68526
68592
  const DEFAULT_TRADING_POLICY = EffectiveTradingPolicySchema.parse({
68527
68593
  autonomyMode: exports.AutonomyMode.ADVISORY_ONLY,
@@ -68542,16 +68608,23 @@ const DEFAULT_TRADING_POLICY = EffectiveTradingPolicySchema.parse({
68542
68608
  maxGrossExposurePct: 100,
68543
68609
  maxNetExposurePct: 100,
68544
68610
  maxLeverage: 1,
68545
- maxSymbolConcentrationPct: 15,
68611
+ maxSymbolConcentrationPct: 8,
68546
68612
  maxSectorConcentrationPct: 30,
68547
- maxOpenPositions: 20,
68613
+ maxOpenPositions: 8,
68548
68614
  maxOpenOrders: 50,
68549
- perTradeEquityAllocationPct: 5,
68550
- perTradeCryptoAllocationPct: 5,
68551
- // 30s wash-trade cooldown matches backend-legacy `TradingPolicy.equityWashTradeCooldownMs` default.
68552
- equityWashTradeCooldownMs: 30_000,
68553
- // Mirrors `defaultRiskConfig.dailyLossLimits.maxDailyLossPercent` (3% intraday loss limit).
68554
- maxDailyLossPercent: 0.03,
68615
+ perTradeEquityAllocationPct: 2,
68616
+ perTradeCryptoAllocationPct: 2,
68617
+ // 5s same-side intraday re-entry cooldown for scalping. FINRA Rule 5210
68618
+ // governs opposing-side wash trades; same-side rapid re-entry off the
68619
+ // same setup is permitted within tighter bounds suited to 5-min-bar
68620
+ // strategies. Backend-legacy `TradingPolicy.equityWashTradeCooldownMs`
68621
+ // default of 30_000 ms remains the canonical row-level fallback for
68622
+ // accounts that have not opted into the scalping profile.
68623
+ equityWashTradeCooldownMs: 5_000,
68624
+ // 2% daily loss cap: tighter than the engine's 3% defaultRiskConfig
68625
+ // because scalping strategies should fail fast — three bad regimes at 3%
68626
+ // each is a 9% intraday burn before the kill-switch fires.
68627
+ maxDailyLossPercent: 0.02,
68555
68628
  macroOverlayEnabled: false,
68556
68629
  sectorOverlayEnabled: false,
68557
68630
  volatilityOverlayEnabled: false,