Strategy-gates-Pattern — Auto-Trading Rule

A detected harmonic pattern never opens a trade on its own. An enabled Strategy that matches the signal is the mandatory gate between pattern detection and trade execution in mi-casa’s auto-trading system.

The Rule

Pattern detected  →  no Strategy match  →  chart display only, no trade
Pattern detected  →  Strategy matches   →  one trade per matching Strategy

Pattern events are detected by ohlc-service and forwarded to mi-casa. The WebSocket broadcast to the frontend is strategy-gated via broadcastPatternEventToUsers.ts — a user only receives a pattern event if they have at least one enabled Strategy matching the event’s patternType, symbol, and timeframe. Strategies therefore govern both what appears on the chart and whether the auto-trade engine opens a paper trade.

Why the Gate Exists

A user may want to trade Gartley patterns on EURUSD 1h but explicitly not on GBPJPY 4h. Without a Strategy, there is no way to express that preference — the engine would have to either trade everything or nothing.

Each Strategy carries its own:

FieldPurpose
strategyTypeWhich harmonic pattern triggers this Strategy
symbolsAllowlist of symbols (e.g. ['EURUSD', 'GBPUSD'])
timeframesAllowlist of timeframes (e.g. ['1h', '4h'])
slMultiplier / tp1Multiplier / tp2Multiplier / tp3MultiplierSL/TP pip-distance multipliers
lotSizePosition sizing
isEnabledMaster on/off switch — disabled strategies are never matched
entryStrategyEntry timing: emerging_prz, prz_touch, candle_close, swing_confirmation
minSignalScoreComposite signal quality threshold (0–1); null = no filter
minRRMinimum R:R ratio (TP1/SL); null = no filter; applies to all strategy types
abcdPrzEntryABCD only: PRZ edge for emerging_prz entries — '1.272' (near, default) or '1.618' (far)

Multiple Strategies can match the same incoming signal — the engine opens one trade per matching Strategy, each tagged with its own strategyId.

Supported Strategy Types

All valid values for the strategyType enum are harmonic:

ValueDescription
cypherCypher
gartleyGartley
batBat
butterflyButterfly
crabCrab
sharkShark
abcdAB=CD

The Auto-Trade Code Path

The harmonic strategy gate lives in backend/services/autoTradingEngine.ts.

Pattern Path — evaluateCandleClosePrz

Triggered by: ohlc:pattern:detected, ohlc:pattern:prz_touch

Event received
  └─ strategyRepository.getEnabledForSignal(userId, patternType, symbol, timeframe)
       └─ filter: entryLagCandles = 0  (D+0 immediate entry)
            └─ for each matching Strategy:
                 ├─ hasOpenStrategyTrade?  → skip if true
                 ├─ maxOpenTrades reached? → skip if true
                 └─ open trade with strategyId set

Pattern Display Is Strategy-Gated

Pattern events flow through broadcastPatternEventToUsers.ts, which applies the same strategy filter before sending data to each connected client:

ohlc-service detects pattern
  ├─ Emits event to mi-casa auto-trade engine  (may or may not open a trade)
  └─ Broadcasts to frontend via WebSocket      (filtered per user — only sent
                                                if the user has a matching
                                                enabled Strategy)

Users without a matching enabled Strategy will not see the pattern on their chart. Strategies therefore govern both trade execution and chart visibility.

What Is NOT Strategy-Gated (by Design)

ActionWhy it bypasses the gate
POST /api/trading/trades with entrySource: 'manual'User-initiated — explicit intent, always allowed
Pending order creationCreated by the engine as a by-product of a matched Strategy with entryLagCandles > 0
Pending order activationActivation is triggered by price hitting the entry level, not a new signal

Creating a Strategy for a Pattern

To automatically trade Gartley patterns on EURUSD and GBPUSD on the 1h and 4h timeframes:

  1. Create a Strategy with strategyType: 'gartley'
  2. Set symbols: ['EURUSD', 'GBPUSD']
  3. Set timeframes: ['1h', '4h']
  4. Configure slPercent, tpPercent, and lotSize
  5. Set isEnabled: true

When ohlc-service next detects a Gartley on EURUSD 1h, the engine calls getEnabledForSignal, finds this Strategy, passes the dedup and cap checks, and opens one trade tagged with strategyId.

A second Strategy — say strategyType: 'gartley' for symbols: ['GBPJPY'] with isEnabled: false — will be found but skipped because it is disabled. The same Gartley signal on GBPJPY 4h with no matching Strategy produces no trade at all.