Gymnasium-compatible trading environment for FX and crypto time series. It
wraps a backtrader simulation behind a standard
gym.Env step/reset interface so reinforcement-learning agents can trade a
historical price feed with realistic order execution, protected stop-loss /
take-profit brackets, margin and solvency accounting, execution-cost models and
session/event context. Every moving part — data feed, broker, strategy
(order execution), preprocessor, reward and metrics — is a plugin selected by
name from a JSON config.
Publication scope (2026-09-14): the additional execution-accounting and trade-reconciliation work is preserved in this research snapshot, not bulk-merged into the default branch. Reproducing a reported experiment requires its pinned environment version, data contract and cost configuration. Do not compare results from different fill or commission models as if they were the same experiment.
The research repository map separates this simulator from data preparation, RL training and real execution. Simulation fidelity and causal inputs need independent tests; neither follows merely from compatibility with the Gymnasium API.
Lifecycle: ACTIVE-CORE. This environment is the execution layer consumed by the agent-multi RL training and optimization pipelines. It is actively maintained; its behavior is part of the evidence contract of ongoing experiments.
Disclaimer: everything in this repository operates on historical or synthetic data in simulation/backtest mode. Nothing here executes real-capital trades, and none of the examples or configurations are financial advice.
Inspect the environment config, observation/action spaces and execution-cost implementation for this revision. Run bounded CPU tests on local fixtures, including timing, episode termination and cost accounting. Report the exact data and environment identities and any limitations. Do not start training, download market data or connect to a venue. Compare agents only when their environment and execution semantics are matched.
Role: provide the trading environment only — observation construction,
order simulation, reward computation and per-episode diagnostics behind the
Gymnasium API (GymFxEnv in app/env.py).
Not responsible for:
- Training agents or optimizing hyperparameters — that is agent-multi.
- Price prediction or feature/label engineering — see predictor and feature-eng.
- Distributed optimization — gym-fx has no DOIN integration of its own; it is driven indirectly when doin-node runs agent-multi experiments.
- Live brokerage connectivity or real order routing.
JSON config ──> app/main.py ──> GymFxEnv (app/env.py)
│ observation: price/returns windows,
│ position, equity, margin, event context
▼
BTBridge (app/bt_bridge.py)
│ discrete/continuous actions ──> orders
▼
backtrader Cerebro simulation
(alternative engines in simulation_engines/,
incl. an optional NautilusTrader adapter)
Key mechanisms, each covered by tests:
- Protected SL/TP execution — with
"require_protected_entries": truethe bridge refuses to start unless the strategy plugin implementsapply_action()(bracket orders), and if the plugin fails at runtime the entry action is rejected and counted, never silently downgraded to a naked market order. Risk-reducing closes remain available. Seeapp/bt_bridge.pyandtests/test_protected_order_execution.py. - Solvency modes —
"solvency_mode":normal_realistic(default; a margin breach terminates the episode) oreasy_chronological_continuation(train-only, enforced by the env: the would-be margin call is recorded, the loss is retained, operational capital is recapitalized as debt and the chronological episode continues). Seetests/test_solvency_modes.py. - Diagnostics for evidence trails — the observation includes price and
returns windows; per-step
infocarries raw event-context and execution values, and the end-of-episode summary containsaction_diagnosticsandexecution_diagnosticscounters (entries seen, protected rejections, forced-flat orders, deadband actions, ...). - Execution-cost and event context — spread/slippage/financing profiles
under
examples/config/execution_cost_profiles/and an OANDA-style session/event calendar (app/oanda_calendar.py) with entry-blocking and forced-flat windows.
- agent-multi consumes this package
through its
gym_fx_envenvironment plugin; agent-multi's SAC/PPO/DQN pipelines and curricula are the primary users of the solvency modes and protected-execution semantics. - predictor and prediction_provider live upstream on the forecasting side and are not imported here.
From setup.py: pandas, backtrader, gymnasium, numpy,
requests; optional extra nautilus pins nautilus_trader==1.230.0. No
python_requires is declared; the environment is exercised in practice on
Python 3.12 (verified below with Python 3.12.13, gymnasium 1.3.0).
git clone https://github.com/harveybc/gym-fx.git
cd gym-fx
pip install -e .
# optional NautilusTrader engine:
pip install -e ".[nautilus]"Unverified in a clean environment — the commands above are the standard editable install; they were not re-executed from scratch for this README. The package imports and the example below were verified in an existing Python 3.12.13 environment with this repository installed editable.
Runs a buy-and-hold driver for 490 steps over the bundled EURUSD sample (verified: exit code 0):
python app/main.py --load_config examples/config/buy_hold.jsonObserved result: prints per-step diagnostics and writes
examples/results/buy_hold_summary.json with final_equity: 9999.99121,
trades_total: 0, plus action_diagnostics (steps: 490,
hold_actions: 489, long_actions: 1) and execution_diagnostics. The
console entry point gym-fx-env (installed by setup.py) invokes the same
app.main:main.
Other repository-owned configs: examples/config/random_driver.json,
examples/config/nautilus_gym_smoke.json.
None directly. gym-fx is a local library; distributed campaigns orchestrate it only through agent-multi (see the agent-multi README).
Configuration is a flat JSON merged over defaults in
app/config.py (CLI flags in app/cli.py
override file values). Plugins are resolved by
app/plugin_loader.py from importlib.metadata entry
points declared in setup.py:
| Entry-point group | Plugins (this package) |
|---|---|
data_feed.plugins |
default_data_feed |
broker.plugins |
default_broker, oanda_broker |
strategy.plugins |
default_strategy, direct_fixed_sltp, direct_atr_sltp |
preprocessor.plugins |
default_preprocessor, feature_window_preprocessor |
reward.plugins |
pnl_reward, sharpe_reward, dd_penalized_reward |
metrics.plugins |
default_metrics, trading_metrics |
Note on preprocessor.plugins: the preprocessors under
preprocessor_plugins/ are local to this repository
but registered into the shared preprocessor.plugins entry-point group also
used by sibling packages (preprocessor,
predictor). If several of those
packages are installed in one environment, the group contains entries from all
of them — including a same-named default_preprocessor from predictor — so
prefer a dedicated environment per application when plugin names matter.
python -m pytest tests --collect-only -q # observed: "84 tests collected in 0.77s"
python -m pytest tests # full run: unverified for this READMEThe suite covers protected order execution, solvency modes, continuous-action
thresholds, execution-cost context, event-context overlays, the
feature-window preprocessor, trading metrics, the OANDA calendar and the
Nautilus engine contracts. Smoke/benchmark utilities live in
tools/ (e.g. tools/smoke_test.py,
tools/check_gym_compliance.py).
results_file(JSON): episode summary — equity, return, drawdown, trade counts,action_diagnostics,execution_diagnostics.save_config(JSON): the fully merged effective config, written back so a run can be reproduced exactly from its emitted config.- Example outputs land under
examples/results/.
Determinism depends on the driver: the bundled deterministic drivers
(buy_hold, fixed data feed) reproduce bit-identical summaries; RL agents on
top add their own seeding (managed by agent-multi).
The default data feed and broker are offline simulations over CSV files; no
network access or credentials are needed. The oanda_broker plugin and the
OANDA calendar can consume broker-formatted data, but this repository ships no
credentials and no live-trading path; do not commit API keys into configs.
Simulation results do not guarantee live performance.
easy_chronological_continuationis train-only by design; the env raises if it is enabled outside training mode. Evaluation always runsnormal_realistic.- No
python_requires/version pinning in packaging metadata yet. - Top-level package names (
app,*_plugins) are shared conventions across sibling repositories; installing several of them into one environment can shadow same-named modules. Use one environment per application, or run from the repository root so local packages win. - The NautilusTrader adapter (
simulation_engines/) is optional and only exercised when thenautilusextra is installed.
- agent-multi — RL trainer/optimizer consuming this env
- doin-node — decentralized optimization runtime (drives agent-multi, not gym-fx directly)
- preprocessor — standalone CSV preprocessing app sharing the
preprocessor.pluginsgroup - predictor — phased deep-learning price prediction
This repository does not currently include a LICENSE file; no license terms are published. Contact the owner before reusing the code.