Safety Mechanisms in Trading Bots
In trading bots, safety mechanisms come before strategy. A bad strategy loses a little; missing safety loses the whole account. Here are the guards I learned to build into live bots.
⚠️ This is educational material, not investment advice. Investment losses are your responsibility.
1. Force Liquidation — Never Hold Overnight
The first rule of intraday strategies: don't carry positions into the next day. Overnight gaps destroy overnight risk. So run a completely separate liquidation goroutine:
strategy engine : enter/exit on gap signals
force liquidate : 15:20 single check → market-order-close all open positions
Separate it as an independent goroutine because it must run at a fixed time regardless of strategy state. Quotes thin before close, so orders may fail. Retry up to 3 times at 1-minute intervals with market orders. Failure triggers immediate alert.
2. Duplicate Entry Guard — Three Layers
Real-time signals fire multiple times per second. Without guards, you'll open the same position twice or thrice. Layer three defenses:
posMu.Lock() // 1) Mutex blocks concurrent entries
defer posMu.Unlock()
if pos.IsOpen { // 2) Already open → skip immediately
return
}
if time.Since(pos.LastOrderTime) < debounce { // 3) Debounce (e.g., 30 sec)
return
}
// After order sent, immediately mark IsOpen=true → next signal is blocked
The trick: immediately mark IsOpen=true after sending the entry order, before the broker responds. If the next signal arrives while you're waiting for fill confirmation, the lock already blocks it.
3. Pre-Entry Gates — Multiple Guards
Before sending an order, pass multiple checkpoints:
- Time gate: Skip first 5 min after open (quotes unstable) and last 10 min before close.
- Extreme move gate: If underlying moved ±15%, treat as anomaly; skip.
- Quote depth gate: If ask-side liquidity × price < half your order size, likely to fail; skip.
- Data freshness gate: If last fill received > 10 sec ago, don't trust the signal.
Philosophy: "Better miss a good opportunity than take a bad entry." These gates implement that.
4. State Persistence — Survive Restarts
Bots crash, deploy, or need maintenance. If state lives only in memory, restart loses what positions are open. Persist core state to JSON files:
bot_state.json : bot running state (running Y/N)
positions.json : open positions (qty, entry, time, IsOpen)
baseline.json : today's opening price baseline (includes trading date)
On restart, read these files to recover. Date checking is critical: if baseline.json's trading date differs from today, discard it and re-capture. Otherwise you'd calculate today's gaps against yesterday's open—disaster.
if saved.TradingDate != today {
baselines = map[string]*BaselineSnapshot{} // date mismatch → wipe
}
If you restart during market hours with open positions and forced-close time has passed, immediately queue those positions for liquidation.
5. Credential Protection — No Plaintext
API keys and secrets never exist in plaintext. Encrypt them with AES-GCM:
gcm, _ := cipher.NewGCM(block)
nonce := make([]byte, gcm.NonceSize())
io.ReadFull(rand.Reader, nonce)
ciphertext := gcm.Seal(nonce, nonce, []byte(plaintext), nil)
Validate input too. If a symbol isn't six digits, don't pass it to the order path—last defense against orders to wrong symbols.
Summary
Safety isn't glamorous but determines bot lifespan. Forced close-out stops overnight risk. Three-layer duplicate guards prevent accidental multi-entry. Pre-entry gates filter bad fills. State files survive crashes. Encrypted credentials block leaks.
None of these are optional for live trading. Without all five, don't move real capital into the bot.
This is educational material, not investment advice. Investment losses are your responsibility.
댓글
댓글 쓰기