@adaptic/utils 0.0.986 → 0.0.988

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