Skip to main content

MangroveAI Python SDK

Discord PyPI Downloads

Python SDK for the MangroveAI trading strategy platform.

Install

pip install mangroveai

The package imports as mangrove_ai (e.g. from mangrove_ai import MangroveAI). The legacy import mangroveai path also still works for backwards compatibility.

Setup

  1. Create an account at mangrovedeveloper.ai
  2. Navigate to Settings > API Keys
  3. Generate a new API key
  4. Set it as an environment variable:

macOS / Linux (bash/zsh):

export MANGROVE_API_KEY=prod_your_key_here

Windows (PowerShell):

$env:MANGROVE_API_KEY = "prod_your_key_here"

Windows (cmd.exe):

set MANGROVE_API_KEY=prod_your_key_here

Private configuration

For an agent or local script, keep the key in private configuration outside your repository. examples/first_call.py reads a JSON file containing api_key and optional base_url, disables dotenv loading, and makes one usage request. Restrict the file's permissions and do not commit it. Existing environment variable and optional mangroveai[dotenv] loading remain supported for compatibility; use load_dotenv=False to disable file discovery.

First API call

from mangrove_ai import MangroveAI

# api_key comes from private configuration; do not paste it into source.
with MangroveAI(api_key=api_key, load_dotenv=False, timeout=15, auto_retry=False) as client:
    metrics = client.users.get_my_metrics()
    print(metrics.messages_count)

This calls GET /api/v1/users/me/metrics with Bearer authentication. It does not create a strategy or launch a backtest. The SDK surfaces 401, 402, 403, 429 and 503 as typed errors, including available retry and correlation fields. It does not purchase access or pay automatically.

The following sections also describe features already present in source but not yet published in the current PyPI 2.0.0 wheel. See the release handoff for release prerequisites.

Quickstart

from mangrove_ai import MangroveAI

client = MangroveAI()  # reads MANGROVE_API_KEY from environment

# List trading signals
signals = client.signals.list(limit=10)
for s in signals.items:
    print(f"{s.name} ({s.category}, {s.signal_type})")

# Get market data
btc = client.crypto_assets.get_market_data("BTC")
print(f"BTC: ${btc.data['current_price']:,.2f}")

# Create a strategy
from mangrove_ai.models import CreateStrategyRequest

strategy = client.strategies.create(CreateStrategyRequest(
    name="RSI Momentum",
    asset="BTC",
    entry=[{"name": "rsi_oversold", "signal_type": "TRIGGER",
            "timeframe": "1d", "params": {"window": 14, "threshold": 30}}],
))

# Run a backtest (blocks until done; async-backed since v1.14, so long
# lookbacks work -- it submits to the async surface and polls internally)
import json
from mangrove_ai.models import BacktestRequest

result = client.backtesting.run(BacktestRequest(
    asset="BTC",
    interval="1d",
    strategy_json=json.dumps({"name": "test", "asset": "BTC",
        "entry": [{"name": "rsi_oversold", "signal_type": "TRIGGER",
                    "timeframe": "1d", "params": {"window": 14, "threshold": 30}}],
        "exit": []}),
    lookback_months=3,
    initial_balance=10000,
    min_balance_threshold=0.1, min_trade_amount=25,
    max_open_positions=3, max_trades_per_day=10,
    max_risk_per_trade=0.02, max_units_per_trade=1000000,
    max_trade_amount=10000000, volatility_window=24,
    target_volatility=0.1,
    # Partial trades-model overrides retain the other server defaults.
    # Loss pauses default to 36 bars, clamped to 24 hours through 14 days.
    execution_config={
        "circuit_breaker": {
            "consecutive_loss_limit": 4,
            "pause_bars": 36,
        }
    },
))
print(f"Trades: {result.trade_count}, Sharpe: {result.metrics.get('sharpe_ratio')}")

Compare circuit-breaker settings by submitting a complete new backtest for each setting over the same original history and seed. Reusing or filtering a prior trade list cannot measure the changed signals, sizing, fees, exits, and account balances produced by a full run.

The regular and Oracle single/bulk backtest request models accept cooldown_model, max_drawdown_limit, and max_drawdown_halt_limit. The SDK places explicitly supplied values in execution_config, where the engine reads them. Omitting a threshold accepts the server default; explicitly passing None disables that guard. Conflicting values in both locations raise ValueError before sending. Disabling drawdown guards alone does not disable loss pauses: a fully unprotected control also needs the explicit bars model and zero short_cooldown_bars and long_cooldown_bars for every active timeframe. Keep valid positive loss limits and window sizes. Legacy cooldown_config supplied on an SDK request is also placed inside execution_config. Align these settings with any configuration embedded in strategy_json or individual bulk strategy configs: Oracle's per-strategy configuration precedence still applies. Preserve all other strategy inputs, fees, and sizing between full runs.

Session authentication

API keys use Bearer authentication and do not refresh. client.auth.login() accepts a Firebase ID token and installs the returned access token for core v1 and v2 requests. Keep the same client open: refresh uses its scoped mg_refresh and mg_csrf cookies plus X-CSRF-Token, with no JSON body. Current login responses omit the body refresh token; older missing or null fields are accepted. auto_auth=True refreshes an expired JWT once, then retries once. Use auto_auth=False to handle expiration yourself. Supplying a body refresh token raises a local configuration error because the current API does not accept it.

Unsupported compatibility methods

execution.update_account, execution.get_position, crypto_assets.risk_analysis and the three retired WhaleAlert methods raise locally before HTTP because the current API does not expose those operations. Use the documented resources. execution.list_positions(open_only=False) includes both states. Legacy status="closed" filters the returned server page locally; offsets still refer to all server rows, so a filtered page can contain fewer than limit rows.

Caller-owned execution and confirmed fills

Mangrove owns enforcement of configured user limits and approval policy. The SDK submits documented requests and preserves Mangrove decisions and audit results; it does not implement a separate trading safety policy.

For an external executor, evaluate_by_object(..., persist=False) proposes orders from the caller's actual ledger. Even an order marked filled in an evaluation is an estimate until that executor confirms it. The result separates:

  • open_positions: the authoritative input book, unchanged by proposed fills.
  • proposed_positions: entry templates with stable position IDs and brackets.
  • proposed_closes: estimated net exit results.
  • closed_trades: confirmed engine-owned simulated fills only.

Both proposal fields carry execution_confirmed=False. Book an entry or close only from the executor's actual fill, including its actual fees and net P&L. Retain returned execution_state risk counters and candle cursors, then overlay the actual account balances and position book before evaluating again. Preserve gross cumulative deposits and the net funding reference separately.

Confirmed close delivery belongs inside the inline strategy:

# strategy contains rules/config plus persisted risk state overlaid with the
# actual ledger. ledger_* values below come from your executor's durable store.
payload = {
    **strategy,
    "closed_positions": ledger_closed_positions,
    "closed_positions_bootstrap_complete": ledger_history_is_complete,
}
result = client.execution.evaluate_by_object(
    payload, open_positions=ledger_open_positions, persist=False,
)

Each close has a stable position_id, exit_timestamp, actual realized_pnl, and the ledger's booked_at timestamp. Deliver the complete initial confirmed history before marking bootstrap complete; an empty complete history is valid for a new account. In the trades model, new entries are held until that initial history is acknowledged. Exits continue, and the returned risk state reports entry_block_reason="close_history_bootstrap_required". This also applies to inline drafts and requests that omit open_positions; omission does not attest an empty history. Keep delivering new closes until the returned risk state acknowledges their position IDs. Do not clear risk state, reset halts, or turn an unfilled proposal into history when retrying. When flat, send explicit open_positions=[].

For evaluate_bulk, put these same three fields, including open_positions, inside each strategy config. Check each result's success independently. persist=True with a saved strategy ID instead uses the engine's simulated fill ledger; it does not confirm execution at an external venue. persist=True without a strategy ID does not confirm fills.

Services

Layer 1: MangroveAI Core API

Service Access Methods Description
client.auth auth.* 5 Login, refresh, API key management
client.strategies strategies.* 9 Strategy CRUD, status, execution state, verify_strategy (pre-backtest conformance check)
client.backtesting backtesting.* 8 Sync/async/bulk backtesting, get_benchmark (buy-and-hold over a window)
client.market_data market_data.* 2 get_market_regime (direction over 90/180/365d + volatility + the lookback in sweep-catalog labels, for crypto and listed stocks, ETFs, commodities and bonds such as SPY, GOLD and CRUDE), classify_market_segment (one named stretch in sweep-catalog labels)
client.config config.* 3 Trading/execution defaults, get_execution_config_schema (each parameter's default, effect, bounds, status)
client.oracle oracle.* 28 SIEVE scoring, parameter sweeps/experiments, corpus data queries, backtests, simulation, leaderboard
client.signals signals.* 8 Signal discovery, evaluation, validation, query_signal_behavior (measured selectivity / firing rate by parameter setting)
client.crypto_assets crypto_assets.* 10 Assets, approved universe, per-asset exchanges, OHLCV, market data
client.execution execution.* 8 Accounts, positions, trades, evaluation
client.on_chain on_chain.* 11 Smart-money flows, DEX/perp trades and token holders (Nansen); retired WhaleAlert compatibility methods fail locally
client.defi defi.* 8 TVL/chain/stablecoins (any plan); token unlocks, perp funding, treasuries, ETF flows, lending rates (DeFiLlama Pro -- requires Pro/Startup/Enterprise, capped at 1,000 calls/account/month)
client.social social.* 3 Topic sentiment, mentions, user influence (X / Twitter)
client.docs docs.* 2 Documentation listing and content

client.config.get_execution_config_schema() makes an explicit server request and exposes the canonical normalized authoring schema as result.json_schema, alongside defaults and the parameter glossary. Older servers may omit this additive field, in which case it is None. Nested glossary metadata includes cooldown fields and the backend's required-field declarations. The SDK does not fetch this metadata automatically or use it to impose trading policy. Authoring guidance is separate from accepted legacy transport shapes; the HTTP boundary does not enforce the entire nested authoring schema.

Layer 2: Knowledge Base API

Service Access Methods Description
client.kb.documents kb.documents.* 3 Document listing, content, sections
client.kb.search kb.search.* 1 Full-text search with BM25 ranking
client.kb.tags kb.tags.* 2 Tag listing and filtering
client.kb.glossary kb.glossary.* 3 Glossary terms and backlinks
client.kb.signals kb.signals.* 2 Signal metadata from KB
client.kb.indicators kb.indicators.* 2 Indicator metadata from KB
client.kb.compute kb.compute.* 2 x402 paid signal/indicator computation

On-chain capability surface

client.on_chain covers Mangrove's supported Nansen Pro operations. Three WhaleAlert methods remain as compatibility stubs and raise locally without making a request:

Method Source What it returns
get_onchain_series(symbol, metrics, date_from, date_to, interval, provider) Nansen Per-bar metric time series (SmartMoneyNetflow, SmartMoneyHoldings, ExchangeNetflow, WhaleNetInflow, HolderConcentration) — one column per metric
get_smart_money_sentiment(symbol) Nansen Single-token accumulation/distribution score
screen_smart_money(chains, timeframe) Nansen Tokens with high smart-money activity
get_smart_money_historical_holdings(chains, date_range, filters, order_by) Nansen Date-stamped holdings snapshots
get_smart_money_dex_trades(chains, filters, order_by) Nansen Live DEX trades by smart-money wallets
get_smart_money_perp_trades(filters, order_by) Nansen (Hyperliquid) Perpetual-futures trades by smart-money wallets
get_token_holders(symbol) Nansen Holder distribution + concentration
get_token_dex_trades(symbol, chain, date_range, filters, order_by) Nansen Single-token DEX trades across all participants
get_token_flows(symbol, chain, date_range, label, filters, order_by) Nansen Per-wallet-category hourly flow rows (label scopes to smart_money/exchange/whale/…; excludes stablecoins)

On-chain time series → signals. get_onchain_series returns a per-bar series for any window — the same call serves a live trailing window (e.g. last 10 days, ending now) or a long historical range. Build a DataFrame with pd.DataFrame(resp.series).set_index("timestamp") and feed it to a mangrove-kb on-chain signal. End-to-end walkthrough: examples/onchain_signals_demo.py.

filters and order_by pass through directly to the upstream Nansen API — restrict by include_smart_money_labels, set value_usd min/max bounds, sort by any field. See examples/on_chain_nansen.py for raw-method snippets.

Oracle — SIEVE + sweep

client.oracle.* is Mangrove's strategy-research engine. Two headline tools:

  • SIEVE scores up to 99 strategy ideas in one call and returns binary go/no-go probabilities (p_trades vs p_no_trades) for whether a strategy will trade. The retired four_class outcome head is None on current responses; do not use it to predict performance or rank strategies.
  • Sweep fans a parameter search into one managed experiment of many backtests and ranks the results.

Score ideas with SIEVE

from mangrove_ai import MangroveAI
from mangrove_ai.models.oracle import SieveScoreRequest, StrategyInput, SignalSpec

client = MangroveAI()  # reads MANGROVE_API_KEY

resp = client.oracle.sieve_score(SieveScoreRequest(strategies=[
    StrategyInput(
        asset="BTC",
        entry=[SignalSpec(name="ema_crossover", signal_type="TRIGGER", timeframe="1h")],
        exit=[SignalSpec(name="rsi", signal_type="FILTER", timeframe="1h")],
    ),
    # ...up to 99 strategies per request
]))

print(f"scored {resp.count} | model {resp.model_version}")
for p in resp.predictions:
    print(f"  go/no-go: {p.binary}")  # {'p_no_trades': .., 'p_trades': ..}
# SIEVE is a go/no-go gate (will it trade?), not a performance prediction:
# backtest the strategies it expects to trade. `four_class` is retired (None).

Run a parameter sweep (experiment lifecycle)

A sweep is a draft experiment you validate, then launch; it fans out into backtests asynchronously. Poll get_experiment / list_results to track it.

# Pick a dataset + execution defaults from the API, then build a config
ds = client.oracle.list_datasets()[0]
exec_config = client.oracle.exec_config_defaults()

config = {
    "name": "ema-sweep-demo",
    "kind": "single",
    "search_mode": "random",
    "seed": 42,
    "n_random": 50,                 # number of random strategies to draw
    "datasets": [ds],
    "random_signals": {
        "n_entry_triggers": 1, "min_entry_filters": 0, "max_entry_filters": 2,
        "min_exit_triggers": 0, "max_exit_triggers": 1,
        "min_exit_filters": 0, "max_exit_filters": 1,
        "n_param_draws": 3, "allowed_categories": None,
    },
    "execution_config": exec_config,
}

created = client.oracle.create_experiment(config)            # -> status "draft"
val = client.oracle.validate_experiment(created.experiment_id)
print(f"valid={val.valid} total_runs={val.total_runs} errors={val.errors}")

if val.valid:                                                # must pass before launch
    client.oracle.launch_experiment(created.experiment_id)   # fans out asynchronously
    status = client.oracle.get_experiment(created.experiment_id)
    print(f"status={status['status']} completed={status.get('completed_runs')}")
    # client.oracle.pause_experiment(id) / delete_experiment(id) to stop or clean up

results = client.oracle.list_results(experiment_id=created.experiment_id, limit=20)

Canonical Sieve and sweep workflows

For the same Sieve and sweep operations advertised by MangroveAI MCP, use client.strategy_workflow.screen_candidates, list_sweep_markets, size_sweep, get_sweep_limits, create_sweep, launch_sweep, get_sweep, list_sweeps, find_sweep_runs, list_run_filters, get_sweep_run, and pause_sweep. These methods call /strategy-workflow/<name> and leave composition, sizing, ranking, ownership and pricing to the server. Load sweeps or sweep-results with client.strategy_workflow.load_skill for the current workflow. Creating a sweep does not launch it; launch only after agreeing to the server's run count. The SDK uses its existing authenticated HTTP transport; it does not add a wallet or sign x402 payments. The agent's existing MCP payer handles wallet access. The lower-level client.oracle.* methods retain their existing raw-engine contracts.

Other client.oracle.* methods

  • Backtests: backtest, backtest_async + backtest_poll, backtest_bulk
  • Corpus query: data_query (curated BigQuery proxy over the results corpus)
  • Simulation: simulate_run, simulate_generate, simulate_presets, simulate_history
  • Results & catalogs: list_results, list_datasets, list_signals, list_templates, exec_config_defaults
  • Leaderboard & live: leaderboard, list_deployed_strategies, get_deployed_strategy_state, get_deployed_strategy_events

Full reference: SIEVE pre-filter guide, SIEVE end-to-end, and the Experiments API reference.

Environment Detection

The SDK auto-detects the environment from your API key prefix:

Prefix Environment API Base URL
prod_ Production https://api.mangrovedeveloper.ai/api/v1
dev_ Development Explicit base_url or MANGROVE_BASE_URL required

Development never falls back to production. A test_ key also requires an explicit base URL or local environment. Base URL overrides apply to v1 and v2; pass a base ending in /api/v1. The Knowledge Base has its own kb_base_url.

Override with explicit parameters:

client = MangroveAI(api_key="...", base_url="http://localhost:5001/api/v1")

Error Handling

from mangrove_ai import MangroveAI, NotFoundError, RateLimitError, APIError

client = MangroveAI()

try:
    strategy = client.strategies.get("nonexistent-id")
except NotFoundError as e:
    print(f"Not found: {e.message} (correlation_id={e.correlation_id})")
except RateLimitError as e:
    print(f"Rate limited, retry after {e.retry_after}s")
except APIError as e:
    print(f"[{e.status_code}] {e.code}: {e.message}")

Pagination

Paginated endpoints return PaginatedResponse[T]:

# Single page
page = client.strategies.list(skip=0, limit=10)
print(f"Showing {len(page.items)} of {page.total}")

# Auto-paginate all items
for strategy in client.strategies.list_iter():
    print(strategy.name)

Examples

See the examples/ directory for working scripts.

Development

git clone https://github.com/MangroveTechnologies/MangroveAI-SDK.git
cd MangroveAI-SDK
pip install -e ".[dev]"
pytest tests/ --ignore=tests/integration  # unit tests
MANGROVE_API_KEY=... pytest tests/integration/ -m integration  # live tests

Metadata

Release files for mangroveai 2.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for mangroveai 2.1.0
File Size Uploaded Provenance Actions
mangroveai-2.1.0.tar.gz 412.3 kB Without provenance Details for mangroveai-2.1.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for mangroveai 2.1.0
File Interpreter ABI Platform Actions
mangroveai-2.1.0-py3-none-any.whl Python 3 none any Details for mangroveai-2.1.0-py3-none-any.whl

Total release size: 516.5 kB

Release files / mangroveai-2.1.0.tar.gz

Download URL mangroveai-2.1.0.tar.gz
Size 412.3 kB
Tags Source
SHA-256 checksum
How to use checksums
b120e9cd0dfa7252a9e2f926b3aefde181e5e032c043dac165635c2422059aab
BLAKE2b-256 checksum
How to use checksums
ee66aa7c9923d01faeff13b27dfc93c5512d31a6f59d67b4734784da32bb60a1
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.16

Release files / mangroveai-2.1.0-py3-none-any.whl

Download URL mangroveai-2.1.0-py3-none-any.whl
Size 104.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
66c63d7eab97ec0aac913dbc5df4ffd00067d3f3db92fd1fac221aeeb58a01eb
BLAKE2b-256 checksum
How to use checksums
5a66ad6d4b95a0acd5014f292faf48e2798149e4bb11e004d7d1dc874dc60174
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.16

Security for mangroveai 2.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

2.1.0 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page