Metadata-Version: 2.4
Name: bt_api_py
Version: 0.15.3
Summary: Implement backtesting and trading of quantitative strategy
Author-email: cloudQuant <yunjinqi@gmail.com>
License: MIT
Project-URL: Homepage, https://github.com/cloudQuant/bt_api_py
Project-URL: Repository, https://github.com/cloudQuant/bt_api_py
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: Implementation :: CPython
Classifier: Operating System :: POSIX :: Linux
Classifier: Operating System :: Microsoft :: Windows
Classifier: Operating System :: MacOS
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: bt_api_base>=0.15.4
Requires-Dist: numpy>=1.26.0
Requires-Dist: python-dotenv>=1.0.0
Requires-Dist: requests>=2.31.0
Requires-Dist: websocket-client>=1.6.0
Requires-Dist: pyyaml>=6.0
Requires-Dist: pandas>=2.0.0
Requires-Dist: aiohttp>=3.9.0
Requires-Dist: spdlog>=2.0.0
Requires-Dist: pytz>=2023.3
Requires-Dist: python-rapidjson>=1.10
Requires-Dist: httpx>=0.27.0
Requires-Dist: pyzmq>=26.0.0
Requires-Dist: pydantic>=2.0.0
Requires-Dist: websockets>=12.0
Requires-Dist: typing-extensions>=4.8.0
Requires-Dist: eval-type-backport>=0.2.0; python_version < "3.10"
Provides-Extra: dev
Requires-Dist: build>=1.0.0; extra == "dev"
Requires-Dist: wheel; extra == "dev"
Requires-Dist: cython; extra == "dev"
Requires-Dist: types-PyYAML>=6.0; extra == "dev"
Requires-Dist: types-pytz>=2023.3; extra == "dev"
Requires-Dist: types-requests>=2.31.0; extra == "dev"
Requires-Dist: pytest>=7.0; extra == "dev"
Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
Requires-Dist: pytest-sugar>=1.0.0; extra == "dev"
Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
Requires-Dist: pytest-timeout>=2.1.0; extra == "dev"
Requires-Dist: pytest-html>=4.0.0; extra == "dev"
Requires-Dist: pytest-rerunfailures>=12.0; extra == "dev"
Requires-Dist: pytest-xdist>=3.0.0; extra == "dev"
Requires-Dist: pytest-benchmark>=4.0.0; extra == "dev"
Requires-Dist: pytest-picked>=0.5.0; extra == "dev"
Requires-Dist: ruff>=0.1.0; extra == "dev"
Requires-Dist: mypy>=1.0; extra == "dev"
Requires-Dist: pre-commit>=3.0.0; extra == "dev"
Requires-Dist: bandit[toml]>=1.7.0; extra == "dev"
Requires-Dist: pip-audit>=2.7.0; extra == "dev"
Requires-Dist: setuptools>=83.0.0; extra == "dev"
Requires-Dist: hypothesis>=6.0.0; extra == "dev"
Requires-Dist: psutil>=5.9.0; extra == "dev"
Requires-Dist: scikit-learn>=1.3.0; extra == "dev"
Requires-Dist: pyarrow>=14.0.0; extra == "dev"
Provides-Extra: security
Requires-Dist: pyjwt>=2.8.0; extra == "security"
Requires-Dist: cryptography>=41.0.0; extra == "security"
Requires-Dist: bcrypt>=4.1.0; extra == "security"
Provides-Extra: visualization
Requires-Dist: matplotlib>=3.7.0; extra == "visualization"
Requires-Dist: pyecharts>=2.0.0; extra == "visualization"
Provides-Extra: monitoring
Requires-Dist: psutil>=5.9.0; extra == "monitoring"
Requires-Dist: aiohttp>=3.9.0; extra == "monitoring"
Provides-Extra: email
Requires-Dist: aiosmtplib>=2.0.0; extra == "email"
Provides-Extra: time
Requires-Dist: ntplib>=0.4.0; extra == "time"
Provides-Extra: ib
Requires-Dist: ib-insync>=0.9.86; extra == "ib"
Provides-Extra: ib-web
Requires-Dist: pyjwt>=2.8.0; extra == "ib-web"
Requires-Dist: cryptography>=41.0.0; extra == "ib-web"
Requires-Dist: playwright>=1.45.0; extra == "ib-web"
Provides-Extra: mt5
Requires-Dist: pymt5>=0.5.0; extra == "mt5"
Provides-Extra: cookies
Requires-Dist: browser-cookie3>=0.19.0; extra == "cookies"
Provides-Extra: all
Requires-Dist: bt_api_py[cookies,dev,email,ib,ib_web,monitoring,mt5,security,time,visualization]; extra == "all"
Provides-Extra: core-reference
Requires-Dist: bt_api_binance>=2.0.0; extra == "core-reference"
Requires-Dist: bt_api_ctp<3.0,>=2.0.2; extra == "core-reference"
Dynamic: license-file

# bt_api_py

[![Python 3.11-3.13](https://img.shields.io/badge/python-3.11--3.13-blue.svg)](https://www.python.org/downloads/)
[![Tests](https://github.com/cloudQuant/bt_api_py/actions/workflows/tests.yml/badge.svg)](https://github.com/cloudQuant/bt_api_py/actions/workflows/tests.yml)

`bt_api_py` is a Python façade for exchange plugins, direct Feed calls, and an optional ZeroMQ forwarding boundary. It is a library and integration framework—not a declaration that every registered plugin or venue is ready for live trading.

Release-blocking CI targets Python 3.11–3.13. Python 3.14 is canary-only.

## Install and diagnose

```bash
python -m pip install bt_api_py
python -m bt_api_py.doctor --bundle core-reference --format json
```

The doctor command verifies installed package metadata and reports plugins as installed, disabled, or unavailable. It does not authenticate to an exchange or place orders.

## Typed order example

```python
from decimal import Decimal

from bt_api_py import BtApi, OrderRequest, OrderType, Side

api = BtApi(exchange_kwargs={"BINANCE___SPOT": {"testnet": True}})
ack_or_venue_result = api.make_order(
    "BINANCE___SPOT",
    OrderRequest(
        symbol="BTCUSDT",
        side=Side.BUY,
        order_type=OrderType.LIMIT,
        quantity=Decimal("0.001"),
        price=Decimal("50000"),
        account_id="paper",
        client_order_id="example-order-1",
    ),
)
```

`OrderRequest` is the cross-transport contract. The historical positional form remains only as a compatibility layer and must include a side-qualified type such as `"buy-limit"`; a bare `"limit"` or `"market"` cannot safely infer side.

## Normalized results and durable execution

The existing `BtApi` methods accept `normalized=True` for standard account,
instrument, position and order results. `poll_event(exchange_name)` returns
standard market, order and trade dictionaries; quantities retain the venue's
native units. Position intent uses `position_side`, `offset`, `position_mode`
and `quantity_unit` on `OrderRequest`, including CTP dated closes and native
order references. Unsupported venue capabilities fail explicitly.

Enable a durable execution session with the optional constructor argument:

```python
api = BtApi(
    exchange_kwargs=exchange_config,  # Supply your configured accounts.
    debug=False,
    execution_config={
        "order_journal": "local-orders.jsonl",
        "account_currency": "USDT",
        "order_poll_interval": 0.2,
    },
)
```

`BtApi` remains the only public trading client. Its internal session owns the
exclusive journal lock, intent persistence, client ID uniqueness, uncertain
execution reconciliation and cumulative fill/fee state. Call
`new_client_order_id(exchange_name)` before binding a local order reference,
submit a typed request with `normalized=True`, then keep polling `poll_event`
even when no market bar arrives. A timeout never triggers a replacement order.
An unresolved historical intent blocks new placements until the original order
is reconciled. Reuse the same journal across restarts and call `close()` when done.

With a session enabled, legacy/raw writes, asynchronous writes and bulk
cancellation are explicitly rejected where they cannot honor its journal
contract. Omitting `execution_config` preserves the historical API behavior.
`get_execution_summary()` reports the session's unresolved orders and fees;
`get_all_balances(normalized=True)` preserves individual account currencies,
and `get_portfolio_balance()` rejects mixed or nonzero unknown currencies.
The session does not contain Backtrader orders, feeds or strategy accounting.

## Direct and forwarding reads

Direct mode preserves the native Feed result shape. In ZMQ mode, typed reads use `Consistency`:

```python
from bt_api_py import Consistency

# With a configured forwarding service and an active market subscription:
snapshot = api.get_tick("SIM___SPOT", "BTC-USDT", consistency=Consistency.CACHE_OK)
```

`LIVE` waits for a post-call event within the configured timeout. `CACHE_OK` only returns a bounded, explicitly stale snapshot; cache misses and timeouts use different domain errors. ZMQ public trades are not part of the current forwarding protocol and fail explicitly instead of falling back to a local Feed.

## Support status

<!-- BEGIN GENERATED:EXCHANGE_SUPPORT_OVERVIEW -->
## Support status

The entries below are evidence tiers, not a count of production-ready exchanges.

| Scope | Tier | Evidence boundary | Current limitation |
| --- | --- | --- | --- |
| core-reference bundle | `experimental` | Bundle metadata for BINANCE___SPOT, OKX___SPOT and CTP___FUTURE; not a live-trading or installed-plugin certification. | Current isolated submodule diagnostic has no initialized plugin worktrees, so package install/import/test certification is pending. |
| other registered plugins | `unverified` | Registry or submodule presence only. | Do not infer REST, WebSocket, paper-trading, or production readiness from registration alone. |

Blocking CI supports Python `3.11`, `3.12`, `3.13`; Python `3.14` is canary-only.

See `docs/operations/support-status-policy.md` for the evidence and expiry rules.
<!-- END GENERATED:EXCHANGE_SUPPORT_OVERVIEW -->

## Contributing and verification

- [Installation](docs/getting-started/installation.md)
- [Runtime architecture](docs/explanation/architecture.md)
- [BtApi reference](docs/reference/bt_api.md)
- [Support-status policy](docs/operations/support-status-policy.md)
- [Submodule validation profiles](docs/ci/submodule-validation-profiles.md)

Use a clean checkout and retain JSON/JUnit/log artifacts when validating exchange plugins. A registry entry, source directory, or historical test number is not release evidence.
