EvalItUp
START FREE
Skip to main content
Python Trade Copier

Python Trade Copier for Algorithmic Trading

Connect your Python scripts, ML bots, and quantitative models directly to your Rithmic prop firm accounts. Local HTTP API with < 5ms latency.

Native HTTP API

EvalItUp exposes a local HTTP API on port 8080. Send a JSON POST from any Python script — no proprietary SDK, no complex wrapper, just standard HTTP.

Why Python for Automated Trading?

Python is the preferred language for algorithmic trading thanks to its powerful libraries (pandas, numpy, scikit-learn, TensorFlow). With EvalItUp, your Python scripts can execute directly on your Rithmic prop firm accounts.

From your ML model to Rithmic execution in a single line of code: requests.post()

Why Use Python with EvalItUp?

Traditional trading platforms don't integrate easily with Python. EvalItUp offers a simple HTTP API that works with any script.

Traditional Integrations

  • Complex proprietary SDKs with limited documentation
  • C++ or Java dependencies difficult to install
  • High latency via bridges or cloud APIs
  • No native multi-account support
  • Constant maintenance during platform updates

With EvalItUp

  • Simple HTTP POST — works with requests, httpx, aiohttp
  • No dependencies: pip install requests and you're ready
  • < 5ms local latency — ideal for HFT
  • Dispatch to unlimited accounts with a single request
  • Stable API — no breaking changes

Complete API Reference

Endpoint

Method:POST
Content-Type:application/json
Bash
http://127.0.0.1:8080/signal/{workflow_id}

Max size: 64 KB

Required Fields

schema_version
"1.0" or "1.1" — Schema version (1.1 adds action, order_id, parent_order_id)
signal_id
Unique signal identifier (UUID recommended)
workflow_id
Target pool/workflow name (case-sensitive)
instrument
Object {exchange, symbol} — e.g., {"exchange": "CME", "symbol": "ESU6"}
side
Direction: BUY, SELL, LONG, SHORT
qty
Number of contracts (positive integer)

Optional Fields

order_type
MARKET (default), LIMIT, STOP, STOP_LIMIT
limit_price
Limit price (required if LIMIT or STOP_LIMIT)
trigger_price
Trigger price (required if STOP or STOP_LIMIT)
bracket
Object {take_profit, stop_loss} for bracket orders
open_close
OPEN or CLOSE — indicates if order opens or closes a position

HTTP Responses

200 OKSignal accepted and dispatched to accounts
{"status": "accepted", "signal_id": "abc-123"}
400 Bad RequestInvalid JSON or missing fields
{"error": "Missing required field: qty"}
404 Not FoundWorkflow/pool not found
{"error": "Workflow not found: xyz"}

Python Code Examples

Copy-paste these examples into your scripts. All use the requests library (pip install requests).

Basic Signal

Sends a simple market order

Python
import requests
import uuid

def send_signal(pool, symbol, side, qty):
    url = f"http://127.0.0.1:8080/signal/{pool}"
    
    signal = {
        "schema_version": "1.0",
        "signal_id": str(uuid.uuid4()),
        "workflow_id": pool,
        "instrument": {
            "exchange": "CME",
            "symbol": symbol
        },
        "side": side,
        "qty": qty
    }
    
    response = requests.post(url, json=signal, timeout=5)
    return response.json()

# Example
result = send_signal("my-pool", "MESU6", "BUY", 2)
print(result)

Signal with Take Profit and Stop Loss

Generates 3 linked orders automatically (entry + TP + SL)

Python
import requests
import uuid

def send_bracket_order(pool, symbol, side, qty, tp_price, sl_price):
    url = f"http://127.0.0.1:8080/signal/{pool}"
    
    signal = {
        "schema_version": "1.0",
        "signal_id": str(uuid.uuid4()),
        "workflow_id": pool,
        "instrument": {
            "exchange": "CME",
            "symbol": symbol
        },
        "side": side,
        "qty": qty,
        "bracket": {
            "take_profit": {
                "limit_price": tp_price
            },
            "stop_loss": {
                "trigger_price": sl_price
            }
        }
    }
    
    response = requests.post(url, json=signal, timeout=5)
    return response.json()

# Example: Buy 1 MES with TP +20 points and SL -10 points
entry_price = 5070.00
result = send_bracket_order(
    pool="scalping-mes",
    symbol="MESU6",
    side="BUY",
    qty=1,
    tp_price=entry_price + 20,
    sl_price=entry_price - 10
)
print(result)

Limit Order

Buys only if price reaches your limit

Python
import requests
import uuid

def send_limit_order(pool, symbol, side, qty, limit_price):
    url = f"http://127.0.0.1:8080/signal/{pool}"
    
    signal = {
        "schema_version": "1.0",
        "signal_id": str(uuid.uuid4()),
        "workflow_id": pool,
        "instrument": {
            "exchange": "CME",
            "symbol": symbol
        },
        "side": side,
        "qty": qty,
        "order_type": "LIMIT",
        "limit_price": limit_price
    }
    
    response = requests.post(url, json=signal, timeout=5)
    return response.json()

# Example: Buy 1 ES at 5050 or less
result = send_limit_order("swing-es", "ESU6", "BUY", 1, 5050.00)
print(result)

Complete EvalItUp Class

Reusable Python wrapper for all your trading projects

Python
import requests
import uuid
from typing import Optional, Literal

class EvalItUpClient:
    def __init__(self, base_url: str = "http://127.0.0.1:8080"):
        self.base_url = base_url
        self.session = requests.Session()
        self.session.headers.update({"Content-Type": "application/json"})
    
    def send_signal(
        self,
        pool: str,
        symbol: str,
        side: Literal["BUY", "SELL"],
        qty: int,
        exchange: str = "CME",
        order_type: str = "MARKET",
        limit_price: Optional[float] = None,
        trigger_price: Optional[float] = None,
        tp_price: Optional[float] = None,
        sl_price: Optional[float] = None
    ) -> dict:
        signal = {
            "schema_version": "1.0",
            "signal_id": str(uuid.uuid4()),
            "workflow_id": pool,
            "instrument": {
                "exchange": exchange,
                "symbol": symbol
            },
            "side": side,
            "qty": qty
        }
        
        if order_type != "MARKET":
            signal["order_type"] = order_type
        if limit_price:
            signal["limit_price"] = limit_price
        if trigger_price:
            signal["trigger_price"] = trigger_price
        
        if tp_price or sl_price:
            signal["bracket"] = {}
            if tp_price:
                signal["bracket"]["take_profit"] = {"limit_price": tp_price}
            if sl_price:
                signal["bracket"]["stop_loss"] = {"trigger_price": sl_price}
        
        url = f"{self.base_url}/signal/{pool}"
        response = self.session.post(url, json=signal, timeout=5)
        return response.json()
    
    def close_position(self, pool: str, symbol: str, side: Literal["BUY", "SELL"], qty: int) -> dict:
        signal = {
            "schema_version": "1.0",
            "signal_id": str(uuid.uuid4()),
            "workflow_id": pool,
            "instrument": {"exchange": "CME", "symbol": symbol},
            "side": side,
            "qty": qty,
            "open_close": "CLOSE"
        }
        url = f"{self.base_url}/signal/{pool}"
        return self.session.post(url, json=signal, timeout=5).json()

# Usage
client = EvalItUpClient()
client.send_signal("my-pool", "MESU6", "BUY", 2)
client.send_signal("my-pool", "MESU6", "BUY", 1, tp_price=5100, sl_price=5050)
client.close_position("my-pool", "MESU6", "SELL", 2)

Async Version (asyncio + aiohttp)

For high-performance bots with parallel processing

Python
import aiohttp
import asyncio
import uuid

async def send_signal_async(pool, symbol, side, qty):
    url = f"http://127.0.0.1:8080/signal/{pool}"
    
    signal = {
        "schema_version": "1.0",
        "signal_id": str(uuid.uuid4()),
        "workflow_id": pool,
        "instrument": {"exchange": "CME", "symbol": symbol},
        "side": side,
        "qty": qty
    }
    
    async with aiohttp.ClientSession() as session:
        async with session.post(url, json=signal) as response:
            return await response.json()

# Send multiple signals in parallel
async def main():
    tasks = [
        send_signal_async("pool-1", "MESU6", "BUY", 1),
        send_signal_async("pool-2", "MNQU6", "BUY", 1),
        send_signal_async("pool-3", "MESU6", "SELL", 1),
    ]
    results = await asyncio.gather(*tasks)
    for r in results:
        print(r)

asyncio.run(main())

Python Use Cases

Machine Learning Trading

Connect your scikit-learn, TensorFlow or PyTorch models. When your model predicts an opportunity, send the signal to EvalItUp.

if model.predict(features) > threshold: send_signal('ml-pool', 'MESU6', 'BUY', 1)

From Backtest to Live

Use the same code for backtest and live. Simply change the execution handler to call the EvalItUp API.

Backtest mode: simulated_fill() | Live mode: send_signal()

Real-Time Data Analysis

Combine pandas and numpy with real-time data feeds. Detect patterns and execute immediately.

WebSocket market data → pandas analysis → signal if condition met

Multi-Strategy Orchestration

Run multiple Python strategies in parallel, each targeting a different pool.

Thread 1: scalping → pool-scalp | Thread 2: swing → pool-swing

Scheduled Trading

Use schedule or APScheduler for time-based executions.

schedule.every().day.at('09:30').do(execute_open_strategy)

Python Framework Integrations

Backtrader

Popular backtesting framework. Create a custom broker that calls the EvalItUp API.

Inherit from bt.BrokerBase and implement submit() with send_signal()

Zipline / Zipline-Reloaded

Used by Quantopian. Implement a custom execution handler.

Create a TradingAlgorithm with handle_data() that calls the API

VectorBT

Ultra-fast vectorized backtesting. Ideal for prototyping.

Use signals generated by VectorBT to trigger live orders

Jupyter Notebooks

Prototype your strategies interactively and execute from the notebook.

Perfect for experimentation and assisted manual trading

Best Practices

Error Handling

Always wrap your API calls in try/except

Python
try:
    result = send_signal(...)
    if result.get('status') != 'accepted':
        logger.error(f"Signal rejected: {result}")
except requests.Timeout:
    logger.error("EvalItUp API timeout")
except requests.ConnectionError:
    logger.error("EvalItUp not reachable")

Logging

Log each signal with its signal_id for debugging

Keep a history of signal_ids to correlate with EvalItUp logs

Simulation Testing

Always test on simulation accounts before going live

Create a 'test-sim' pool connected only to simulation accounts

Rate Limiting

Avoid sending too many signals too quickly

1 signal per second is a good starting point

Tutorial: First Python Signal

Follow this guide to send your first signal from a Python script.

1

1. Install the requests library

The standard HTTP library for Python

Bash
pip install requests
2

2. Launch EvalItUp

Open EvalItUp and connect to your Rithmic accounts. The local API starts automatically on http://127.0.0.1:8080

3

3. Create a Test Pool

In EvalItUp, create a pool named 'python-test' and add a simulation account to it.

4

4. Send a Test Signal

Run this code. You should see status 200 and the signal in EvalItUp → Activity.

Python
import requests

response = requests.post(
    "http://127.0.0.1:8080/signal/python-test",
    json={
        "schema_version": "1.0",
        "signal_id": "test-001",
        "workflow_id": "python-test",
        "instrument": {"exchange": "CME", "symbol": "MESU6"},
        "side": "BUY",
        "qty": 1
    }
)

print(response.status_code)  # 200
print(response.json())       # {"status": "accepted", ...}
5

5. Verify in EvalItUp

Open the Activity tab in EvalItUp. You'll see your 'test-001' signal and the orders sent to pool accounts.

Python Trade Copier FAQ

Does EvalItUp need to be open for the API to work?

Yes. The HTTP API is hosted by the EvalItUp application. If the app is closed, requests will fail with ConnectionError.

Can I use the API from a remote server?

By default, the API listens on 127.0.0.1 (localhost). For remote access, use an SSH tunnel or configure a secure reverse proxy.

What is the API latency?

< 5ms locally. The time includes validation and sending to Rithmic accounts. Rithmic execution adds 1-5ms.

Can I send multiple signals in parallel?

Yes. Use asyncio with aiohttp, or ThreadPoolExecutor. Each signal is processed independently.

Does the API support authentication?

Optionally. Configure a Bearer token in EvalItUp → Settings → API, then add the Authorization: Bearer YOUR_TOKEN header.

How do I debug if my signals aren't executing?

1) Check HTTP code (200=OK, 400=JSON error, 404=pool not found). 2) Check EvalItUp logs. 3) Verify workflow_id = exact pool name.

Can I use this API with other languages?

Yes. It's a standard HTTP API. It works with curl, JavaScript, C#, Go, Rust, or any language capable of sending HTTP POSTs.

How do I integrate with Backtrader or Zipline backtest?

Create a custom broker/execution handler that calls send_signal() instead of simulating fills. Keep the same strategy logic.

Ready to Connect Your Python Scripts?

Local HTTP API, < 5ms latency, no SDK required. Start free with 2 accounts.