DEV Community

Manish Kumbham
Manish Kumbham

Posted on AI-assisted

I built an MCP server for crypto trading strategies, design decisions and what I learned

I've been building a crypto trading platform (dMoERA) that runs algorithmic bots on ETH/BTC/SOL pairs. The core problem I kept hitting: the strategy development loop is brutal. You write a bot, manually backtest it, eyeball the results, try 20 variations, repeat. So I wrapped the whole thing in an MCP server and open-sourced the client.

dMoERA MCP Demo

dMoERA Creator Studio

Repo: github.com/CacheCarti/dmoera-mcp
Smithery: smithery.ai/servers/mk9654/dMoERA-Creator

It's not a trading bot. It's not a signal service. It's an MCP interface that lets any MCP-compatible agent (Claude, Cursor, Windsurf, Devin) interact with a running trading platform, discover markets, backtest strategies, submit them for validation, and monitor live performance.

This post is about the design decisions that mattered.


How the strategy contract works

Strategies subclass a Strategy class and implement on_bar(self, ctx) -> Signal. The signal is just:

  • direction (long/short/flat)
  • confidence (0-1)
  • stop_loss_bps
  • take_profit_bps
  • horizon_seconds

That's it. The bot never sees leverage, position sizing, or portfolio state, the router handles all of that.

This was a deliberate decision: bots that know their leverage tend to overfit to it. If a bot knows it has 10x, it'll optimize for 10x-specific risk profiles that stop working the moment leverage changes. By isolating the signal from the execution, the same bot can run at 1x for a conservative user and 10x for an aggressive one without changing a single line.

The ctx object gives access to:

  • OHLCV bars (configurable lookback)
  • A feature catalog: funding rates, Fear & Greed index, order book imbalance, ATR, RSI, volume profile
  • Current market regime (trending / ranging / crisis) with a crisis score

All features are pre-computed and cached. The strategy just reads them.

class MyStrategy(Strategy):
    METADATA = {
        "name": "SMA Crossover",
        "domain": "eth_usdc",
        "declared_sl_bps": 150.0,
        "declared_tp_bps": 300.0,
        "declared_hold_seconds": 3600,
        "warmup_bars": 20,
        "required_features": [],
    }

    def on_bar(self, ctx):
        closes = ctx.closes(lookback=20)
        if len(closes) < 20:
            return None
        fast = sum(closes[-5:]) / 5
        slow = sum(closes) / 20
        if fast > slow:
            return ctx.signal(
                direction=SignalDirection.LONG,
                confidence=0.7,
                stop_loss_bps=150.0,
                take_profit_bps=300.0,
                horizon_seconds=3600,
            )
        return None
Enter fullscreen mode Exit fullscreen mode

Validation

Submitted strategies go through a 7-stage validation pipeline:

  1. Static check — metadata validation, SL/TP ceiling, code safety scan
  2. In-sample backtest — seeded RNG, no wall clock, no network
  3. Out-of-sample — 40% of data held out, never seen during in-sample
  4. Walk-forward — 4 rolling windows, train on each, test on the next
  5. Randomized start — 10 backtests with different start dates, checks for start-date luck
  6. Perturbation — inject small noise into OHLCV, checks for overfitting to exact prices
  7. Holdout — final test on data the strategy has never seen

A strategy has to pass all 7 to go live. The holdout stage is the gate, if it fails there, it doesn't deploy regardless of how good earlier stages looked.

After passing two stages, you can choose to make the code open-source so others can fork and improve it.


Tournament system

Bots compete in 3-day rounds across 6 domains (ETH/BTC/SOL spot + scalp). Scoring is:

  • 50% rolling Sharpe ratio
  • 30% rolling return (last 25 trades, compounded)
  • 20% consistency (win rate × trade volume)

Top 3 per domain win USDT from the reward pool. No user following needed, your bot competes on its own metrics.


What this does NOT do

  • No execution layer in the MCP server. The server is a thin API client. It talks to a running dMoERA backend over HTTP.
  • No published performance numbers. The bots on the platform have live track records you can inspect, but I'm not going to cherry-pick numbers for this post. Call get_bot_profile and see for yourself.
  • No code execution in the MCP server itself. Backtesting runs on the backend in a sandboxed process. The server just passes strategy code via HTTP.
  • Not a framework for building your own backtester. This is specifically for the dMoERA platform's strategy contract.

Tools (16)

Category Tools
Discovery list_domains, list_bots, get_bot_profile, get_feature_catalog
Market data get_market_regime, get_current_prices
Strategy dev sandbox_backtest, submit_strategy, list_strategies, get_strategy_report
Marketplace get_marketplace_bots, get_tournament_status
Open source open_source_strategy, fork_strategy, get_open_source_leaderboard, delist_strategy

Resources (2)

  • creator-api://docs — Full strategy contract documentation
  • creator-api://strategy-template — Copy-pasteable template

Auth model

Public tools (market data, leaderboard, tournament) work with no key. Authenticated tools (backtest, submit, fork) need a personal access token.

Transports

  • stdio: python mcp_creator_server.py (for Claude Desktop, Cursor, Windsurf)
  • Streamable HTTP: https://dmoera.xyz/mcp (for Smithery, remote clients)

Setup

{
  "mcpServers": {
    "dmoera-creator": {
      "command": "python",
      "args": ["/absolute/path/to/dmoera-mcp/mcp_creator_server.py"],
      "env": {
        "DMOERA_API_URL": "https://dmoera.xyz",
        "DMOERA_API_KEY": "your_optional_personal_access_token"
      }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

The API key is optional for public tools. Create a personal access token at dmoera.xyz under Settings → API Keys to backtest, submit, fork, open-source, or delist strategies.


GitHub: github.com/CacheCarti/dmoera-mcp
Smithery: smithery.ai/servers/mk9654/dMoERA-Creator
Platform: dmoera.xyz

MIT license. Happy to answer questions or take criticism. If you see design flaws in the strategy contract or validation approach or any nice-to-haves :) I genuinely want to know.

Top comments (0)