Skip to content

Latest commit

 

History

2 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ETF Limit-Order Execution

Cont/Hawkes order-flow estimates plus a Gymnasium environment for selling a child order with price-time queue priority.

The policy is a small numeric network (REINFORCE by default, optional Stable-Baselines3 PPO). This is not LLM / verl / GRPO training.

L2 ticks / orders / trades  (kept local)
  → Cont λ(i), μ, θ(i)·x   (+ Hawkes μ for thin names)
  → fill odds / waiting time
        ↓
Gymnasium LimitOrderEnv
  numeric state: depth, imbalance, queue, leftover, time, NAV
  actions: wait | ask+0/+1/+2 | cancel | market 50% | market 100%
        ↓
REINFORCE  or  SB3 PPO
  vs TWAP / VWAP / random   (implementation shortfall)

Libraries used as references, not forks:

Install

cd etf-execution
pip install -e ".[dev]"
pytest -q
python -m etf_execution eval
python -m etf_execution train --episodes 40

PPO (optional):

pip install -e ".[train]"
python -m etf_execution train --ppo --episodes 40

What the env does

The agent is a seller. Each step it can rest on the ask, cancel, or cross the spread. Background flow arrives from estimated Cont intensities; market-order intensity can self-excite with a Hawkes kernel. A buy that walks the ask fills the agent in price-time order.

Reward is minus implementation shortfall versus arrival mid, minus leftover inventory at the horizon, minus a small NAV residual and taker penalty. Unfilled size is dumped as a market order at the last step so fill rate is comparable to TWAP.

Estimate intensities from your own L2

Column names follow a Cont-style notebook: time, price, size, side, orderid on orders; bidorderid / askorderid / price on trades; bid1…ask5, bsize1…asize5 on ticks. The aggressor of a trade is the later order id.

from etf_execution.cont.estimate import estimate_intensities
from etf_execution.data.synthetic import make_synthetic_day

orders, trades, ticks = make_synthetic_day()
ix = estimate_intensities(orders, trades, ticks)
print(ix.mu, ix.lambda_by_level, ix.fill_probability(1))

The public repo ships synthetic tapes only. Do not commit exchange L2 dumps. Drop private CSVs under data/raw/ (gitignored).

Out of scope

verl, GRPO, LLM policies, FinRL forks, and publishing proprietary A-share L2. Matching/gateway C++ stays outside this Python research env.

About

Cont/Hawkes order-flow estimates plus a Gymnasium PPO environment for limit-order execution

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages