Skip to content

algotrade-education/Group04

Repository files navigation

MomentumMicrostructure

  • Nguyen Ngoc Duy Tan - 22125090
  • Group 04

Note: Run commands from the project root directory: momentum_microstructure_project/

Abstract

This project develops a rule-based intraday trading system for VN30F1M futures using microstructure-confirmed momentum. Instead of relying only on price momentum, the strategy requires confirmation from order-book imbalance, spread quality, breakout behavior, and ATR-based risk controls. The project also includes an improved regime-adaptive strategy that trades momentum in trending regimes and allows mean-reversion entries in ranging regimes when price is stretched from VWAP and the order book supports a reversal.

The implementation covers the research-to-paper-trading workflow up to the paper trading stage. It includes data processing, feature engineering, strict and regime-adaptive signal generation, spread-aware and fee-aware backtesting, parameter optimization scaffolding, PaperBroker connectivity, Redis market-data integration, live order placement, and order/fill logging.

The latest available paper-trading logs show that the infrastructure is operational: 95 FIX orders were sent, 61 were accepted, 34 were rejected, 44 fill events were recorded, 34 unique orders were filled, 116 contracts were filled, and the total filled notional was approximately 23.50B VND. However, the current local research dataset contains only one historical feature row, so these paper-trading metrics prove execution connectivity and strategy behavior, not yet statistical profitability.

Introduction

Vietnam's derivatives market gives traders an opportunity to trade VN30 index futures intraday. However, discretionary intraday trading is difficult because the market moves quickly, order-book conditions change rapidly, and manual execution can be affected by emotion, delay, and inconsistent risk control.

This project proposes an automated paper-trading pipeline for VN30F1M. The core idea is that price momentum alone is often noisy. A momentum signal is more meaningful when it is supported by market microstructure:

  • price breaks out of a recent intraday range,
  • short-term EMA momentum is aligned with the breakout,
  • order-book imbalance confirms buying or selling pressure,
  • the spread remains tradable,
  • exits are controlled by ATR stop, take-profit, trailing stop, and timeout.

During development, the project was extended with a regime-adaptive layer. This layer classifies the market as trending, ranging, wide-spread, dead-flat, or high-volatility unstable. Trend-following entries are only allowed in trending conditions. Mean-reversion entries are allowed in ranging conditions when price is stretched away from VWAP/rolling mean and order-book pressure turns back toward the mean.

Background

EMA

The Exponential Moving Average (EMA) gives more weight to recent prices. In this project, three EMAs are used:

  • fast EMA: 8 bars,
  • slow EMA: 21 bars,
  • trend EMA: 55 bars.

The momentum gap is calculated as:

momentum_gap = fast_ema - slow_ema

The momentum slope is the change in this gap:

momentum_slope = momentum_gap.diff()

ATR

Average True Range (ATR) is used to estimate short-term volatility. The project uses an ATR window of 20 bars. ATR controls stop-loss distance, take-profit distance, and trailing-stop behavior.

Order-Book Imbalance

Order-book imbalance measures whether visible depth is stronger on the bid side or ask side. The project uses the first three book levels:

order_imbalance = (bid_depth - ask_depth) / (bid_depth + ask_depth)

Positive imbalance suggests stronger bid-side demand. Negative imbalance suggests stronger ask-side pressure.

Spread

Spread is calculated as:

spread = ask_price_1 - bid_price_1

The strategy only trades when the spread is within a configured tick range. In the current configuration, valid spread is between 1 and 4 ticks.

VWAP and Z-Score

The regime-adaptive strategy uses VWAP and price z-score to identify ranging-market mean-reversion opportunities:

  • price below VWAP with positive imbalance may support a long mean-reversion entry,
  • price above VWAP with negative imbalance may support a short mean-reversion entry.

Trading Hypothesis

Original Hypothesis

VN30F1M intraday momentum is more reliable when price momentum is confirmed by market microstructure. A trade should only be opened when price movement, breakout behavior, order-book pressure, and spread quality all support the same direction.

Improved Hypothesis

VN30F1M short-horizon momentum is only worth trading when the market is in a tradable trending regime and the move is confirmed by persistent order-book imbalance plus above-normal matched volume. In ranging regimes, small mean-reversion trades are allowed only when price is stretched from VWAP/rolling mean and book pressure turns back toward the mean. Dead, high-volatility unstable, and wide-spread regimes stay flat.

Strategy Rules

Preconditions

  • Instrument: VN30F1M futures.
  • Default live symbol: HNXDS:VN30F2605.
  • Tick size: 0.1.
  • Contract multiplier: 100000.
  • Default position size: 6 contracts.
  • Only one position should be managed at a time.
  • Default live entry mode: regime_adaptive.
  • Project endpoint: paper trading only.

Strict Momentum Breakout Strategy

The strict strategy is implemented in src/strategy/microstructure_momentum.py.

Open a long position when all conditions are true:

  • account is flat,
  • cooldown is 0,
  • long_breakout is true,
  • momentum_gap > 0,
  • momentum_slope > 0,
  • last_price > trend_ema,
  • order_imbalance >= 0.12,
  • spread is between 1 and 4 ticks.

Open a short position when all conditions are true:

  • account is flat,
  • cooldown is 0,
  • short_breakout is true,
  • momentum_gap < 0,
  • momentum_slope < 0,
  • last_price < trend_ema,
  • order_imbalance <= -0.12,
  • spread is between 1 and 4 ticks.

Exit conditions:

  • ATR stop loss,
  • ATR take profit,
  • ATR trailing stop,
  • momentum failure,
  • maximum holding time.

Regime-Adaptive Strategy

The improved strategy is implemented in src/strategy/regime_adaptive.py.

No entry is allowed in these regimes:

  • wide_spread,
  • dead_flat,
  • high_vol_unstable.

Trending long requires:

  • long_breakout,
  • momentum_gap > 0,
  • momentum_slope > 0,
  • last_price > trend_ema,
  • imbalance_ema >= 0.12,
  • persistent buying for 3 bars,
  • volume_z >= 0.25.

Trending short requires:

  • short_breakout,
  • momentum_gap < 0,
  • momentum_slope < 0,
  • last_price < trend_ema,
  • imbalance_ema <= -0.12,
  • persistent selling for 3 bars,
  • volume_z >= 0.25.

Ranging long requires:

  • price_zscore <= -1.35,
  • vwap_deviation < 0,
  • order_imbalance > 0.

Ranging short requires:

  • price_zscore >= 1.35,
  • vwap_deviation > 0,
  • order_imbalance < 0.

Data

Data Sources

The project supports two data paths:

  1. Research data:

    • data/raw_ticks.csv, if available.
    • Existing data/intraday_features.csv, if it has enough rows.
    • Sample JSON from ../redis_latest.json as fallback.
  2. Live paper-trading data:

    • Redis market data through RedisMarketDataClient.
    • PaperBroker order and FIX logs.

Live Market Fields

The live runner builds 1-minute bars using:

  • last_price,
  • bid_price_1, bid_quantity_1,
  • ask_price_1, ask_quantity_1,
  • bid_price_2, bid_quantity_2,
  • ask_price_2, ask_quantity_2,
  • bid_price_3, bid_quantity_3,
  • ask_price_3, ask_quantity_3,
  • total_matched_quantity.

Feature Output

The processed feature file is saved as:

data/intraday_features.csv

Key generated features include:

  • order_imbalance,
  • spread,
  • mid_price,
  • fast_ema,
  • slow_ema,
  • trend_ema,
  • momentum_gap,
  • momentum_slope,
  • atr,
  • rolling_high,
  • rolling_low,
  • long_breakout,
  • short_breakout,
  • volume_delta,
  • volume_z,
  • vwap,
  • price_zscore,
  • vwap_deviation,
  • trend_strength,
  • range_atr_ratio,
  • imbalance_ema.

Implementation

Environment Setup

Create and activate a virtual environment:

python3 -m venv .venv
source .venv/bin/activate

On Windows PowerShell:

python -m venv .venv
.\.venv\Scripts\Activate.ps1

Install dependencies:

pip install -r requirements.txt

Create an environment file:

cp .env.example .env

Fill in the required PaperBroker and market-data credentials.

Project Structure

momentum_microstructure_project/
├─ config/
│  └─ config.yaml
├─ data/
│  ├─ intraday_features.csv
│  ├─ signals.csv
│  ├─ strategy_comparison.csv
│  ├─ optimization_results.csv
│  └─ live_trade_log.csv
├─ logs/
│  ├─ paperbroker_20260423.log
│  ├─ paperbroker_20260424.log
│  ├─ paperbroker_20260427.log
│  ├─ paperbroker_20260428.log
│  ├─ paperbroker_20260429.log
│  ├─ paperbroker_20260504.log
│  └─ paperbroker_20260505.log
├─ src/
│  ├─ data/
│  │  ├─ sample_market_loader.py
│  │  └─ process_intraday.py
│  ├─ strategy/
│  │  ├─ microstructure_momentum.py
│  │  └─ regime_adaptive.py
│  ├─ backtest/
│  │  └─ intraday_backtest.py
│  ├─ papertrade/
│  │  ├─ market_data.py
│  │  └─ papertrade_client.py
│  └─ utils/
│     └─ optimize.py
├─ test/
│  ├─ close_long_5_vn30.py
│  ├─ 01_simple_login.py
│  ├─ 06_market_data_subscribe.py
│  └─ 10_max_placeable.py
├─ live_strategy_runner.py
├─ run_research_pipeline.py
├─ run_papertrade_check.py
├─ requirements.txt
└─ README.md

Research Pipeline

Run:

python run_research_pipeline.py

This pipeline:

  1. loads research market data,
  2. builds intraday features,
  3. generates baseline and regime-adaptive signals,
  4. runs spread-aware and fee-aware backtests,
  5. compares long, short, and both-side evaluations,
  6. runs parameter optimization when enough data is available,
  7. writes a research report to data/research_report.md.

Backtest Model

The backtester is implemented in:

src/backtest/intraday_backtest.py

Backtest assumptions:

  • signal from bar i-1 is executed on bar i,
  • buy execution price is ask plus slippage,
  • sell execution price is bid minus slippage,
  • fee per contract is 20000 VND,
  • slippage is 1 tick,
  • default size is 6 contracts,
  • daily loss limit is 1500000 VND,
  • losing-trade cooldown is 4 bars.

Reported metrics:

  • total trades,
  • net PnL,
  • win rate,
  • average PnL per trade,
  • maximum drawdown,
  • profit factor,
  • Sharpe-like metric,
  • long/short trade breakdown,
  • longest losing streak.

Current Research Result

At the current project state, the local research dataset is too small for a valid statistical conclusion:

  • data/intraday_features.csv: 1 data row,
  • data/signals.csv: 1 data row,
  • data/strategy_comparison.csv: 0 trades and 0 net PnL across tested strategies,
  • data/optimization_results.csv: 243 parameter combinations, but all with 0 trades because the dataset has only 1 bar.

Therefore, the research pipeline is implemented, but profitability, Sharpe, drawdown control, and out-of-sample alpha are not yet proven.

Optimization

The optimization module is implemented in:

src/utils/optimize.py

The grid currently tests:

Parameter Values
fast_ema 6, 8, 10
slow_ema 18, 21, 26
imbalance_threshold 0.08, 0.12, 0.16
breakout_lookback 15, 20, 30
take_profit_atr 2.0, 2.4, 3.0

The optimizer writes:

data/optimization_results.csv

The current optimization output should be interpreted only as a code-path test because the local research dataset is not yet large enough.

Paper Trading

Connectivity Check

Run:

python run_papertrade_check.py

This checks:

  • REST reachability,
  • PaperBroker environment variables,
  • FIX/socket configuration,
  • market-data environment variables.

It does not place orders.

Live Strategy Runner

Run:

python live_strategy_runner.py

Useful optional arguments:

python live_strategy_runner.py --symbol HNXDS:VN30F2605
python live_strategy_runner.py --qty 6
python live_strategy_runner.py --start-position 5 --entry-price 2018.3

The live runner:

  • connects to Redis market data,
  • builds rolling 1-minute bars,
  • computes features,
  • evaluates the regime-adaptive strategy by default,
  • checks broker capacity before opening,
  • places limit orders through PaperBroker,
  • logs order events to data/live_trade_log.csv,
  • listens for accepted/rejected order events,
  • uses a fee-aware profit guard for exits and reversals.

Fee Guard

The live runner uses the following fee logic:

  • fee per contract per side: 20000 VND,
  • tick size: 0.1,
  • contract multiplier: 100000,
  • tick value: 10000 VND per tick per contract,
  • round-trip fee break-even: 4 ticks,
  • default buffer: 2 ticks,
  • minimum profit threshold: 6 ticks.

Paper-Trading Metrics

The latest available logs cover:

logs/paperbroker_20260423.log
logs/paperbroker_20260424.log
logs/paperbroker_20260427.log
logs/paperbroker_20260428.log
logs/paperbroker_20260429.log
logs/paperbroker_20260504.log
logs/paperbroker_20260505.log

Across these logs:

Metric Value
FIX orders sent 95
Accepted new orders 61
Rejected orders 34
Fill events 44
Unique filled orders 34
Accepted-to-filled unique order rate 55.7%
Total filled quantity 116 contracts
Buy filled quantity 67 contracts
Sell filled quantity 49 contracts
Total filled notional ~23.50B VND

Daily breakdown:

Date Sent Accepted Fill Events Filled Qty Filled Notional
2026-04-23 1 1 0 0 0.00B VND
2026-04-24 4 0 0 0 0.00B VND
2026-04-27 50 21 0 0 0.00B VND
2026-04-28 28 27 29 58 ~11.78B VND
2026-04-29 2 2 1 5 ~1.01B VND
2026-05-04 3 3 4 16 ~3.23B VND
2026-05-05 7 7 10 37 ~7.47B VND

Live Signal Metrics

The live intent log is:

data/live_trade_log.csv

Current range:

2026-04-24T10:56:59 to 2026-05-05T14:04:58+07:00

Event counts:

Event Count
signal_skipped_no_capacity 428
open_skipped 110
order_accepted 56
order_rejected 33
open_long 12
open_short 9

Logged strategy-reason signals:

Signal Branch Count
mean_reversion_long 4
mean_reversion_short 2
momentum_sniffing_long 3
momentum_sniffing_short 2

Mean-reversion evidence:

Branch Average z-score Average VWAP deviation Average imbalance
mean_reversion_long -1.975 -1.7475 0.2505
mean_reversion_short 1.44 0.87 -0.3087

Momentum-sniffing evidence:

Branch Average gap Average slope Average imbalance EMA Average volume z
momentum_sniffing_long 2.9965 0.5083 0.4744 1.1967
momentum_sniffing_short -0.5714 -0.2050 -0.1701 1.00

These metrics show that the live strategy is producing decisions from the intended feature logic. They do not prove profitability.

Limitations

The project currently has two important limitations:

  1. Research limitation:

    • The local historical dataset has only 1 feature row.
    • Backtest and optimization outputs are not statistically meaningful yet.
  2. Execution limitation:

    • Many signals are skipped due to capacity constraints.
    • The live runner still needs stronger order-state and broker-position synchronization to avoid repeated open attempts when orders are pending or positions are already filled.

Next Steps

  1. Add multi-session VN30F1M historical data to:

    data/raw_ticks.csv
    
  2. Rerun:

    python run_research_pipeline.py
  3. Evaluate real in-sample and out-of-sample metrics:

    • net PnL,
    • Sharpe-like metric,
    • maximum drawdown,
    • win rate,
    • profit factor,
    • long/short breakdown,
    • parameter robustness.
  4. Add post-trade analytics from PaperBroker fills:

    • realized PnL,
    • average fill price,
    • slippage,
    • holding time,
    • fill rate,
    • rejection reasons.
  5. Improve live execution state:

    • prevent repeated open orders while an order is pending,
    • reconcile accepted orders with actual fills,
    • sync real broker position before each new entry,
    • adjust position size when broker capacity is below the default 6 contracts.

Conclusion

This project successfully implements a VN30F1M paper-trading pipeline based on microstructure-confirmed momentum. The system can process live market data, compute intraday features, generate strict and regime-adaptive signals, send orders through PaperBroker, and record accepted/rejected/fill events.

The current strongest evidence is operational: the system has sent 95 FIX orders, filled 116 contracts, and handled approximately 23.50B VND in paper-trading filled notional. The strategy logic is also visible in logged signal reasons, including mean-reversion and momentum-sniffing branches.

The strategy is not yet proven profitable because historical research data is still insufficient. The next major milestone is to add multi-session VN30F1M intraday data and run a proper in-sample, optimization, and out-of-sample validation workflow.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages