# trading-ig
[](https://crates.io/crates/trading-ig)
[](https://docs.rs/trading-ig)
[](https://github.com/tibs245/trading-ig-rust/actions/workflows/ci.yml)
[](https://github.com/tibs245/trading-ig-rust/actions/workflows/audit.yml)
[](LICENSE)
[](https://www.rust-lang.org)
[](https://crates.io/crates/trading-ig)
> ## 🤖 About this crate
>
> This crate was **generated by [Claude Opus](https://www.anthropic.com/claude)
> (Anthropic)**, working from the Python library
> [`ig-python/trading-ig`](https://github.com/ig-python/trading-ig) as the
> reference specification. The Rust API mirrors the Python one endpoint-for-
> endpoint. Huge thanks to the original `trading-ig` authors and contributors
> — without their work (and their BSD-3 license) this port wouldn't exist.
Async Rust client for the [IG Markets](https://labs.ig.com/) REST and
Lightstreamer streaming APIs.
- **Crate**: <https://crates.io/crates/trading-ig>
- **Docs**: <https://docs.rs/trading-ig>
- **Repository**: <https://github.com/tibs245/trading-ig-rust>
- **Changelog**: [`CHANGELOG.md`](CHANGELOG.md)
## Install
```toml
[dependencies]
trading-ig = "0.1"
# Optional features:
# trading-ig = { version = "0.1", features = ["stream", "polars"] }
```
## Goals
- **Async-first** (`tokio`), `reqwest` under the hood.
- **Strongly typed**: all requests/responses modelled with `serde`.
- **Composable**: usable as a library independently of any framework.
- **Minimal dependencies**.
- **Structured logs/tracing** via the `tracing` crate.
- **Well-tested**: HTTP responses are covered by mock-server tests built
from reusable fixtures.
## Quick start
```rust
use trading_ig::{IgClient, Environment, Credentials};
#[tokio::main]
async fn main() -> trading_ig::Result<()> {
let client = IgClient::builder()
.environment(Environment::Demo)
.api_key(std::env::var("IG_API_KEY")?)
.credentials(Credentials::password(
std::env::var("IG_USERNAME")?,
std::env::var("IG_PASSWORD")?,
))
.build()?;
client.session().login().await?;
let accounts = client.accounts().list().await?;
for account in accounts {
println!("{} ({})", account.account_name, account.account_id);
}
Ok(())
}
```
### Examples
Three self-contained examples live in [`examples/`](examples/):
| [`login_and_list_accounts`](examples/login_and_list_accounts.rs) | Log in (v3) and print all account IDs |
| [`search_market_and_get_history`](examples/search_market_and_get_history.rs) | Search for EUR/USD, fetch the last hour of minute bars |
| [`open_then_close_position`](examples/open_then_close_position.rs) | Type-state builder syntax for opening and closing a position |
All examples read credentials from `IG_API_KEY`, `IG_USERNAME`, and `IG_PASSWORD`:
```bash
IG_API_KEY=xxx IG_USERNAME=you IG_PASSWORD=secret \
cargo run --example login_and_list_accounts
```
## 🔒 Recommended for funded accounts
For any account that holds real money (live, or funded demo), we
**recommend enabling the `encryption` feature** and using
`session().login_with_encryption()` instead of `session().login()`.
The password is then RSA-encrypted client-side with IG's public key
before transmission — it never appears in plaintext in any
intermediate proxy or server-side log, even in the event of a
TLS MITM or compromised CA.
```toml
[dependencies]
trading-ig = { version = "0.1", features = ["encryption"] }
```
```rust
client.session().login_with_encryption().await?;
// instead of:
// client.session().login().await?;
```
See [`SECURITY.md`](SECURITY.md) for the full rationale and our
disclosure policy.
## Cargo features
| `rustls-tls` | yes | TLS via `rustls` |
| `native-tls` | no | TLS via system OpenSSL |
| `stream` | no | Lightstreamer streaming client |
| `encryption` | no | Encrypted-password login (RSA) |
| `polars` | no | Conversions from tabular API responses to `DataFrame` |
| `live` | no | Compile the live integration test suite (read-only path) |
| `live-trading` | no | Also compile write/mutation live tests (implies `live`) |
### `polars` feature
Enable the `polars` feature to convert tabular API responses directly into
[Polars](https://docs.rs/polars) `DataFrame`s for analysis:
```toml
[dependencies]
trading-ig = { version = "0.1", features = ["polars"] }
```
```rust
use trading_ig::dataframe::IntoDataFrame;
// Convert a list of open positions into a DataFrame.
let positions = client.dealing().positions().list_v2().await?;
let df = positions.to_dataframe()?;
println!("{df}");
// Convert historical prices into a DataFrame (one row per bar).
let prices = client.prices().history_v3(&epic, Default::default()).await?;
let df = prices.to_dataframe()?;
println!("{df}");
```
The `IntoDataFrame` trait is implemented on `Vec<Account>`,
`Vec<PositionV2>`, `Vec<WorkingOrderV2>`, `HistoricalPrices`,
`Vec<Activity>`, `Vec<Transaction>`, `Vec<MarketSummary>`, and
`Vec<Sentiment>`.
## Live integration tests
A separate test file (`tests/live_integration.rs`) exercises the real IG Demo
API end-to-end. All tests are `#[ignore]`d and require explicit credentials,
so they never run in CI.
**Read-only tests** (session, accounts, markets, prices, positions, watchlists,
client sentiment, history):
```bash
IG_API_KEY=your-key IG_USERNAME=you IG_PASSWORD=secret \
cargo test --features live --ignored --test live_integration
```
**Write / mutation tests** (watchlist create/delete, preferences round-trip)
additionally require the `live-trading` feature **and** `IG_LIVE_TRADING_OK=1`:
```bash
IG_API_KEY=your-key IG_USERNAME=you IG_PASSWORD=secret IG_LIVE_TRADING_OK=1 \
cargo test --features live-trading --ignored --test live_integration
```
If `IG_API_KEY` is absent the whole suite skips gracefully, so
`cargo test --all-features` in CI passes without hitting the network.
## Contributing
After cloning, opt into the project's git hooks:
```bash
git config core.hooksPath .githooks
```
This enables:
- **pre-commit** — runs `cargo fmt --check` and `cargo clippy --all-targets
--all-features --no-deps -- -D warnings` on commits that touch Rust or
Cargo files. Skipped for doc-only / fixture-only commits.
- **pre-push** — runs `cargo test --all-targets --all-features` before
pushing to a remote.
Skip a check if you really need to: `git commit --no-verify` /
`git push --no-verify`. The CI workflow runs the same checks regardless,
so anything you bypass locally will fail in PR.
## Project knowledge
Internal conventions, architecture decisions, and the IG API spec live
under [`_knowledge/`](_knowledge/). Start with
[`_knowledge/index.md`](_knowledge/index.md) — it lists every file with
a one-line summary so you can load only what you need.
## License
BSD-3-Clause, mirroring the original [`trading-ig`](https://github.com/ig-python/trading-ig)
Python project.