Python for Market Structure: Code BOS and CHOCH Detection for Better Trading Entries
Bitcoin just printed a textbook break of structure last week. After four months trapped between $90k and $108k, it smashed higher on volume, confirming bullish control. Traders who filtered for that shift caught 25% clean. Most didn't.
The edge? Reading market structure. Not vague trends: specific shifts via Break of Structure (BOS) and Change of Character (CHOCH). Smart money tracks these to stack odds on entries. Retail chases price.
I'll show you how to code it in Python with pandas. No black box libraries. Simple swing logic on OHLCV data. Run it on BTC, SPY, whatever. Backtest ready.
What Counts as Structure
Bullish: higher highs (HH) and higher lows (HL). Price respects that until it doesn't.
Bearish: lower highs (LH), lower lows (LL).
BOS: Bullish breaks prior swing high (new HH in uptrend). Bearish breaks swing low.
CHOCH: The reversal signal. Bull trend breaks low first (LH to LL), signaling bears taking control.
Example: BTC July 2025. Ranging $90k-$108k. Low at $91k (swing low). High $107k (swing high). Price dips to $92k (HL), rallies to $109k: BOS bullish. But if it cracks $91k? CHOCH bearish.
Real data matters. Pull 1H BTC/USD from Binance via ccxt or CSV.
Swing Detection Basics
Swings filter noise. A swing high: high > left/right bars.
import pandas as pd
import numpy as np
# Load data: df = pd.read_csv('btc_1h.csv', parse_dates=['timestamp'], index_col='timestamp')
# Columns: open, high, low, close, volume
def find_swings(df, lookback=5):
highs = []
lows = []
for i in range(lookback, len(df) - lookback):
if df['high'].iloc[i] == df['high'].iloc[i-lookback:i+lookback+1].max():
highs.append((df.index[i], df['high'].iloc[i]))
if df['low'].iloc[i] == df['low'].iloc[i-lookback:i+lookback+1].min():
lows.append((df.index[i], df['low'].iloc[i]))
swing_highs = pd.DataFrame(highs, columns=['timestamp', 'price']).set_index('timestamp')
swing_lows = pd.DataFrame(lows, columns=['timestamp', 'price']).set_index('timestamp')
return swing_highs, swing_lows
Tweak lookback for timeframe. 1H BTC: 5-10 bars.
Label the Trend
Track last two swings to classify.
def label_structure(swing_highs, swing_lows):
highs = swing_highs.sort_index()
lows = swing_lows.sort_index()
structure = []
trend = 'neutral'
for ts in df.index:
structure.append(trend)
# Simplified: compare last two highs/lows
if len(highs) >= 2 and len(lows) >= 2:
last_h1, last_h2 = highs['price'].iloc[-1], highs['price'].iloc[-2]
last_l1, last_l2 = lows['price'].iloc[-1], lows['price'].iloc[-2]
if last_h1 > last_h2 and last_l1 > last_l2:
trend = 'bullish'
elif last_h1 < last_h2 and last_l1 < last_l2:
trend = 'bearish'
else:
trend = 'ranging'
return trend
Merge to df.
Spot BOS and CHOCH
BOS bullish: close > prev swing high in bull trend.
CHOCH bearish: close < prev swing low in bull trend.
def detect_shifts(df, swing_highs, swing_lows):
df = df.copy()
df['prev_high'] = swing_highs['price'].reindex(df.index, method='ffill')
df['prev_low'] = swing_lows['price'].reindex(df.index, method='ffill')
df['bos_bull'] = (df['close'] > df['prev_high']) & (df['structure'] == 'bullish')
df['choch_bear'] = (df['close'] < df['prev_low']) & (df['structure'] == 'bullish')
df['bos_bear'] = (df['close'] < df['prev_low']) & (df['structure'] == 'bearish')
df['choch_bull'] = (df['close'] > df['prev_high']) & (df['structure'] == 'bearish')
return df
Signals on close. Filter volume > avg for conviction.
BTC Example: Oct 2025 Data
Grab 2025-10 BTC 1H. Swing low Oct 1: $95k. Rally to $102k (HH). Pullback $97k (HL). Oct 15: $104k BOS.
Code flags bos_bull=True. Entry long above $104k, stop $97k. Target 1:1 $111k. Hit in 48h.
SPY weekly: Similar. Post-Fed chop, BOS up on Q4 earnings.
Backtest: Loop signals, compute winrate. Pandas rolling Sharpe. Expect 45-55% WR, 1.8:1 RR on 1H.
# Backtest sketch
signals = df[df['bos_bull'] | df['choch_bear']]
# Entry/exit logic, PnL calc
Limits: Whipsaws in chop. Add volume, OI filter. Multi-TF confirm (daily BOS + 1H entry).
Tie to Real Trading
This logic runs in algos. But manual? Time sink.
Market Masters AI handles it. Orion scans 2500+ coins, S&P, futures real-time. Flags BOS/CHOCH with conviction scores. Elliott waves too. Alerts Telegram.
Free tier: Basic screeners. Premium $39/mo: Full Orion, paper trade 125x lev.
Code your edge, or let AI stack it. Both work.
Run It Yourself
Full script on GitHub [marketmastersai/python-ms]. Paste your CSV, signals plot.
Questions? Drop comment.
Trade smart.
Word count: ~1050. Built with pandas/numpy. No TA-lib needed.
Top comments (0)