@adaptic/utils 0.0.985 → 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({});
@@ -68462,6 +68515,26 @@ const EffectiveTradingPolicySchema = objectType({
68462
68515
  perTradeEquityAllocationPct: numberType(),
68463
68516
  /** Percentage of the crypto allocation slice of account equity allocated per crypto trade. Canonical replacement for legacy AlpacaAccount.cryptoTradeAllocationPct. */
68464
68517
  perTradeCryptoAllocationPct: numberType(),
68518
+ /**
68519
+ * Wash-trade cooldown period in milliseconds for equities. Defines the
68520
+ * minimum elapsed time between opposing-side fills on the same symbol per
68521
+ * FINRA Rule 5210, mirroring the 30s default already enforced for crypto.
68522
+ * Mirrors `TradingPolicy.equityWashTradeCooldownMs` in backend-legacy.
68523
+ * Optional so that legacy snapshots that pre-date this field continue to
68524
+ * parse cleanly; consumers should fall back to a 30_000ms static default
68525
+ * when undefined.
68526
+ */
68527
+ equityWashTradeCooldownMs: numberType().int().nonnegative().optional(),
68528
+ /**
68529
+ * Maximum daily portfolio loss as a fraction of account equity, evaluated
68530
+ * intraday from the broker's `equity` vs `last_equity` delta. Breach
68531
+ * activates a 24h `BLOCK_NEW_OPENS` halt per Reg-T daily-loss-limit
68532
+ * controls. Optional so legacy snapshots parse cleanly; consumers
68533
+ * should fall back to the static default in `defaultRiskConfig.dailyLossLimits.maxDailyLossPercent`
68534
+ * (3%) when undefined. Range constrained to [0, 1) — a 100% daily-loss
68535
+ * threshold would be nonsensical.
68536
+ */
68537
+ maxDailyLossPercent: numberType().min(0).max(1).optional(),
68465
68538
  macroOverlayEnabled: booleanType(),
68466
68539
  sectorOverlayEnabled: booleanType(),
68467
68540
  volatilityOverlayEnabled: booleanType(),
@@ -68491,9 +68564,14 @@ const EffectiveTradingPolicySchema = objectType({
68491
68564
  });
68492
68565
 
68493
68566
  /**
68494
- * Conservative default trading policy used as the baseline when no
68495
- * user-customized policy exists. All nested preference sub-objects are
68496
- * 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).
68497
68575
  *
68498
68576
  * Key choices:
68499
68577
  * - Advisory-only autonomy (no autonomous execution)
@@ -68502,6 +68580,14 @@ const EffectiveTradingPolicySchema = objectType({
68502
68580
  * - No shorting or margin (user must opt-in)
68503
68581
  * - All protective overlays disabled (user must opt-in)
68504
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
68505
68591
  */
68506
68592
  const DEFAULT_TRADING_POLICY = EffectiveTradingPolicySchema.parse({
68507
68593
  autonomyMode: exports.AutonomyMode.ADVISORY_ONLY,
@@ -68522,12 +68608,23 @@ const DEFAULT_TRADING_POLICY = EffectiveTradingPolicySchema.parse({
68522
68608
  maxGrossExposurePct: 100,
68523
68609
  maxNetExposurePct: 100,
68524
68610
  maxLeverage: 1,
68525
- maxSymbolConcentrationPct: 15,
68611
+ maxSymbolConcentrationPct: 8,
68526
68612
  maxSectorConcentrationPct: 30,
68527
- maxOpenPositions: 20,
68613
+ maxOpenPositions: 8,
68528
68614
  maxOpenOrders: 50,
68529
- perTradeEquityAllocationPct: 5,
68530
- perTradeCryptoAllocationPct: 5,
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,
68531
68628
  macroOverlayEnabled: false,
68532
68629
  sectorOverlayEnabled: false,
68533
68630
  volatilityOverlayEnabled: false,