I’m building a Polymarket Trading bot in Python, and one problem keeps coming up: a trading strategy can work well in one market condition and fail badly when the environment changes. Instead of letting the bot use the same strategy all the time, I’m experimenting with Hidden Markov Models (HMMs) to detect the current market regime and use that information to decide which strategy should run.
The idea is simple:
Don’t just ask the bot whether there is a trading signal. Ask whether the current market regime is suitable for that signal.
This post explains the architecture, the Python implementation, and what I think is useful—and potentially dangerous—about this approach.
My broader project is a Python-based automated trading system for Polymarket.
The repository is:
Benjam1nCup/Polymarket-trading-bot-python-V2
The goal isn't to create a black-box "AI trading bot."
I’m more interested in building a modular system where each component has one job:
Market Data
↓
Feature Engineering
↓
Regime Detection
↓
Strategy Selection
↓
Risk Management
↓
Order Execution
↓
Monitoring
This makes it easier to test individual components and replace them later.
Imagine a bot using momentum.
When a market is trending:
Price → ↑ ↑ ↑ ↑
A momentum strategy might have favorable conditions.
But when the market becomes choppy:
Price → ↑ ↓ ↑ ↓ ↑ ↓
the same strategy can repeatedly enter at the wrong time.
This suggests a better architecture:
Market Data
│
▼
Regime Detection
│
┌─────────────┼─────────────┐
▼ ▼ ▼
Stable Trending Stressed
│ │ │
▼ ▼ ▼
Mean Reversion Momentum Risk Off
│ │ │
└─────────────┼─────────────┘
▼
Risk Engine
│
▼
Execution
The regime model doesn't have to predict the final outcome of a prediction market.
Instead, it answers:
"What kind of market are we currently observing?"
An HMM assumes there is some hidden state behind the data.
For a trading system, I might define three states:
State 0 → Stable / Low Volatility
State 1 → Trending / Momentum
State 2 → High Volatility / Stressed
We don't directly observe these states.
What we observe is market data:
Returns
Volatility
Volume
Spread
Order-book imbalance
Momentum
Liquidity
The HMM attempts to infer the hidden state that most likely generated those observations.
It also learns transition probabilities.
For example:
Stable → Stable 91%
Stable → Trending 7%
Stable → Stressed 2%
The exact values are learned from data; these numbers are only illustrative.
I'm using hmmlearn for the initial prototype.
Install:
pip install numpy pandas hmmlearn matplotlib
Start with historical market data:
import numpy as np
import pandas as pd
df = pd.read_csv("market_data.csv")
df["return"] = np.log(
df["price"] / df["price"].shift(1)
)
df["volatility"] = (
df["return"]
.rolling(20)
.std()
)
df["momentum"] = (
df["price"].pct_change(10)
)
df = df.dropna()
Then create the feature matrix:
features = df[
[
"return",
"volatility",
"momentum"
]
].values
Now train a three-state Gaussian HMM:
from hmmlearn.hmm import GaussianHMM
model = GaussianHMM(
n_components=3,
covariance_type="full",
n_iter=1000,
random_state=42
)
model.fit(features)
And predict the most likely regime:
df["regime"] = model.predict(features)
We can also inspect the transition matrix:
print(model.transmat_)
And the model's regime probabilities:
probabilities = model.predict_proba(features)
df["p_regime_0"] = probabilities[:, 0]
df["p_regime_1"] = probabilities[:, 1]
df["p_regime_2"] = probabilities[:, 2]
This is more useful than simply getting:
regime = 1
because we can see how confident the model is.
For example:
Stable: 0.10
Trending: 0.84
Stressed: 0.06
That gives the trading system more information.
This is an important detail.
The model doesn't automatically know:
0 = Stable
1 = Trending
2 = Stressed
The state labels are arbitrary.
After training, I inspect each state's statistics:
summary = df.groupby("regime").agg(
mean_return=("return", "mean"),
volatility=("volatility", "mean"),
momentum=("momentum", "mean"),
observations=("regime", "count")
)
print(summary)
I can then interpret the states based on their characteristics.
For example:
Regime 0
Low volatility
Low momentum
→ Stable
Regime 1
Higher momentum
Positive returns
→ Trending
Regime 2
Very high volatility
Large price movements
→ Stressed
The interpretation needs to be validated rather than assumed.
This is where the project gets interesting.
I don't want the HMM to directly place orders.
Instead:
def choose_strategy(regime):
if regime == "TREND":
return "momentum"
if regime == "STABLE":
return "mean_reversion"
if regime == "STRESSED":
return "risk_off"
return "no_trade"
The architecture becomes:
regime = detect_regime(market_data)
strategy = choose_strategy(regime)
if strategy == "momentum":
signal = momentum_signal(market_data)
elif strategy == "mean_reversion":
signal = mean_reversion_signal(market_data)
elif strategy == "risk_off":
signal = None
else:
signal = None
Then the signal goes through another layer:
Signal
↓
Risk Check
↓
Position Size
↓
Exposure Check
↓
Execution
This separation is intentional.
The model shouldn't be able to bypass risk controls just because it has high confidence.
One experiment I'd like to explore is using the regime probability itself.
For example:
REGIME_MULTIPLIERS = {
"STABLE": 1.0,
"TREND": 1.0,
"STRESSED": 0.25,
}
def calculate_position_size(
base_size,
regime,
confidence
):
multiplier = REGIME_MULTIPLIERS.get(
regime,
0.0
)
return base_size * multiplier * confidence
So instead of:
Signal = BUY
→ always trade $100
the system could think:
BUY
+
Trending probability = 84%
+
Risk limits passed
→ trade according to sizing rules
And:
BUY
+
Trending probability = 42%
→ perhaps don't trade
This is an experiment, not a claim that probability-scaled sizing is optimal.
The initial prototype only needs a few features.
Returns
Momentum
Acceleration
Rolling volatility
Volume
Available liquidity
Recent traded volume
Bid/ask spread
Bid depth
Ask depth
Order-book imbalance
Time to resolution
Market duration
Distance from resolution
Recent event/news activity
The interesting part is that prediction markets aren't exactly traditional financial markets.
The time-to-resolution dimension can potentially be very important.
For the actual implementation, the model needs reliable market data and the execution system needs a clean interface to the exchange.
The official Polymarket documentation is the best place to start for current API behavior:
The documentation covers areas such as market data, order books, trading, authentication, orders, and real-time updates.
I would strongly recommend building against the current official documentation rather than copying an old API example from a random tutorial.
The system currently makes the most sense to me as seven components:
┌─────────────────────────────┐
│ 1. DATA COLLECTION │
│ Prices / Order Book / Trades│
└─────────────┬───────────────┘
↓
┌─────────────────────────────┐
│ 2. FEATURE ENGINEERING │
│ Returns / Volatility / etc. │
└─────────────┬───────────────┘
↓
┌─────────────────────────────┐
│ 3. REGIME DETECTION │
│ HMM │
└─────────────┬───────────────┘
↓
┌─────────────────────────────┐
│ 4. STRATEGY ENGINE │
│ Momentum / Mean Reversion │
└─────────────┬───────────────┘
↓
┌─────────────────────────────┐
│ 5. RISK ENGINE │
│ Size / Limits / Kill Switch │
└─────────────┬───────────────┘
↓
┌─────────────────────────────┐
│ 6. EXECUTION ENGINE │
│ Orders / Cancels / Fills │
└─────────────┬───────────────┘
↓
┌─────────────────────────────┐
│ 7. MONITORING │
│ Logs / P&L / Alerts │
└─────────────────────────────┘
The key idea is modularity.
If the HMM doesn't work, I should be able to remove it without destroying the execution engine.
If a new strategy is better, I should be able to add it without rewriting the data pipeline.
There are a few things I'm deliberately trying to avoid.
An HMM isn't magic.
It doesn't guarantee profitable trades.
A model can look amazing in-sample and fail immediately in production.
A theoretical signal isn't the same thing as an executable trade.
Spread, liquidity, slippage, latency, partial fills, and order-book changes all matter.
The model should produce information.
The risk engine should decide whether the trade is allowed.
This is probably one of the easiest ways to fool yourself.
If the model sees future information during training or feature generation, your backtest isn't representative of live trading.
I would rather use walk-forward testing:
Train
────────────────────
Test
─────
Train
───────────────────
Test
─────
Train
───────────────────
Test
─────
For example:
Train: January → March
Test: April
Train: February → April
Test: May
Train: March → May
Test: June
This is much closer to the actual production process.
This is the question I care about most.
Not:
"Can I train an HMM?"
That's easy.
The real question is:
Does regime detection provide incremental value compared with a simpler strategy?
I'd compare:
Baseline
↓
Momentum strategy
vs.
Volatility filter
↓
Momentum strategy
vs.
HMM
↓
Momentum strategy
And then evaluate them out-of-sample.
If a simple volatility threshold performs as well as the HMM, the HMM may not be worth the added complexity.
That's a useful result too.
I don't want to judge the system using P&L alone.
I'd track:
Total return
Maximum drawdown
Sharpe ratio
Sortino ratio
Win rate
Profit factor
Average trade
Turnover
Slippage
Execution latency
And specifically for the HMM:
Regime duration
Regime transition frequency
Probability confidence
Performance by regime
False regime changes
Strategy performance by regime
The most interesting analysis might be:
Strategy Performance
────────────────────
Stable ███████████
Trending ███████████████
Stressed ███
If the strategy performs poorly in stressed conditions, the HMM could potentially be useful as a risk filter.
But that needs to be demonstrated with out-of-sample data.
The HMM itself isn't what I find most interesting.
The architecture is.
Instead of:
Market → Signal → Order
I'm trying:
Market
↓
"What environment are we in?"
↓
Regime
↓
"What strategy fits this environment?"
↓
Signal
↓
"Is the risk acceptable?"
↓
Risk Engine
↓
Order
That's a much more interesting way to think about automated trading systems.
I think regime detection makes sense as a strategy-selection and risk-control layer, but I would be skeptical of anyone presenting an HMM by itself as a source of consistent profits.
The strongest reason to use it is that markets are not stationary.
A strategy can work during a trending environment and fail during a noisy environment. A regime model gives us a structured way to test whether strategy performance actually changes across different market states.
But there's an important burden of proof:
The HMM needs to beat simpler baselines out-of-sample after realistic execution costs.
If it doesn't, complexity isn't justified.
That's the experiment I'd rather run than simply optimize the model until the backtest looks good.
My next experiments would be:
Bid/ask imbalance
Depth
Spread
Liquidity
Trade intensity
HMM
vs.
Rolling volatility
vs.
Moving-average regime
vs.
No regime filter
No random train/test split.
Include:
Spread
Slippage
Latency
Partial fills
Order rejection
Liquidity constraints
I want to see something like:
CURRENT MARKET
───────────────
Regime: TRENDING
Confidence
████████████████░░░░ 84%
Strategy
Momentum
Risk Level
Medium
Trading
ENABLED
This would make the system much easier to monitor.
If you're starting from scratch, I'd recommend going through these in sequence.
My practical introduction covers building a Python-based 5-minute crypto Up/Down trading bot:
How to Build a Polymarket Trading bot — 5-Minute Crypto Up/Down Market Trading Bot in Python
This article covers a broader architecture with multiple automated strategies:
Building a Professional Polymarket Trading System — 12 Automated Strategies
The Python bot repository:
Benjam1nCup/Polymarket-trading-bot-python-V2
For current Polymarket API information:
Not necessarily.
I think it's better viewed as a market-regime model that can help decide which strategy should be active.
Not inherently.
The HMM is primarily identifying statistical market states. A separate model or strategy would need to generate the actual directional signal.
Three is a reasonable starting experiment:
Stable
Trending
Stressed
But I wouldn't assume three is optimal. The data should determine whether additional states provide meaningful information.
No.
The entire point of the experiment is to test whether it provides incremental value over simpler alternatives.
Yes.
The cleanest approach is to add the regime model between feature engineering and the strategy engine.
I'd start with:
Historical Data
↓
Features
↓
HMM
↓
Regime Visualization
Only after that would I connect the regime model to strategy selection and eventually live execution.
No.
This is a technical exploration of automated trading-system architecture. Prediction-market trading involves substantial risk, and historical or simulated performance does not guarantee future results.
The idea behind this project is straightforward:
A Polymarket Trading bot shouldn't necessarily behave the same way in every market environment.
I'm experimenting with Hidden Markov Models as a way to identify those environments and make the trading system more adaptive.
The architecture I'm working toward is:
Market Data
↓
Feature Engineering
↓
HMM Regime Detection
↓
Strategy Selection
↓
Risk Management
↓
Execution
↓
Monitoring
The HMM isn't the magic ingredient.
The interesting part is creating a system where market conditions influence strategy selection and risk, while the final decision still passes through independent risk and execution controls.
My biggest question going forward isn't:
"Can I make the backtest profitable?"
It's:
"Does regime detection actually improve the system out-of-sample after costs, slippage, and realistic execution?"
That's the experiment I'm building next.
If you're interested in the implementation, you can follow the project here:
GitHub — Benjam1nCup/Polymarket-trading-bot-python-V2
And if you're building your own integration, start with the official Polymarket documentation.