DEV Community

Cover image for I Build Custom Trading Bots for Deriv and MT4/MT5 — Here's What That Actually Looks Like
Precious Lyna Anusiem
Precious Lyna Anusiem

Posted on

I Build Custom Trading Bots for Deriv and MT4/MT5 — Here's What That Actually Looks Like

Let me tell you about an order I completed two weeks ago because it's a good illustration of what this work actually involves.

A trader in South Africa — manual EUR/USD strategy, 15-minute chart, EMA crossover with RSI confirmation — needed his system running during London open. He works days. London open is 9 AM GMT, which means he's already two hours into his workday by the time the best setups show up. Two years of solid manual results, locked behind a scheduling problem.

He sent me his rules. I built it. Eight days later he had a Python bot running his exact strategy, logging every trade to SQLite, firing Telegram alerts to his phone, with a full risk management module that mirrors how he trades manually: 1% per trade, 2.5% daily loss ceiling, hard stop.

That's the job. Here's everything else worth knowing about it.


The technical stack I work with

For Deriv (binary options + synthetic indices):

Python 3.11 over the Deriv WebSocket API (wss://ws.binaryws.com/websockets/v3). Async tick subscriptions, rolling buffer for indicator calculation, SQLite for trade and P&L persistence, Telegram Bot API for alerts. Deployed on Render's free tier for 24/7 operation.

The architecture I've settled on after building several of these:

# Simplified core loop structure
async def on_tick(tick_data):
    symbol = tick_data['symbol']
    price  = tick_data['quote']

    buffers[symbol].append(price)

    if len(buffers[symbol]) < MIN_BUFFER:
        return  # Not enough data yet

    if not safety_checks_pass(symbol):
        return  # Daily limits, cooldown, concurrent cap

    signal = score_signal(buffers[symbol], symbol)

    if signal:
        await execute_layered_entry(symbol, signal)
        await notify_telegram(symbol, signal)
        log_to_db(symbol, signal)
Enter fullscreen mode Exit fullscreen mode

Everything safety-critical — daily P&L, drawdown tracking, signal count — goes to SQLite, not memory. A bot that resets its daily loss counter on crash is a bot that will eventually blow an account.

For MT4/MT5:

MQL4 or MQL5 depending on the client's platform. I have 5 EAs published on the MQL5 Marketplace so this is well-trodden territory. The delivery is a compiled .ex4 or .ex5 file plus the source .mq4/.mq5. Clients who want to see under the hood get the source. Clients who just want it running get the compiled file plus the parameter documentation.


The signal architecture I apply across most builds

Most bots I'm asked to build fall into one of two categories:

Mean reversion (typical for synthetic indices — Deriv's Volatility 10, Volatility 25):
Price oscillates. You detect overextension and bet on the return to mean. The indicators that matter here: RSI at extremes, Bollinger Band touches, Rate of Change fading at a peak. Weighted scoring so no single indicator fires a trade alone.

Trend following (typical for real forex pairs — EUR/USD, GBP/USD, XAU/USD):
Price trends directionally. You identify the trend, wait for a pullback, enter in the trend direction. EMA crossovers for trend identification, RSI for momentum confirmation, direction flip detection for pullback entry.

The scoring system I built for my own Deriv bot (the one that hit 71% live) works like this:

fall_score = 0
rise_score = 0

# RSI scoring
if rsi > 78:             fall_score += 3
elif rsi > 70:           fall_score += 2
if rsi < 22:             rise_score += 3
elif rsi < 30:           rise_score += 2

# Bollinger Bands
if price >= upper_bb * 0.999:   fall_score += 3
if price <= lower_bb * 1.001:   rise_score += 3

# Rate of Change momentum
if roc < -0.02:   fall_score += 2
if roc > 0.02:    rise_score += 2

# Direction flip (pullback detection)
if flipped_to_down:   fall_score += 2
if flipped_to_up:     rise_score += 2

# Only fire on unambiguous signals
if fall_score >= 6 and fall_score > rise_score:
    fire_trade("FALL")
elif rise_score >= 6 and rise_score > fall_score:
    fire_trade("RISE")
Enter fullscreen mode Exit fullscreen mode

I adapt this framework to each client's specific logic. The scoring threshold and weights change. The indicators change. The underlying architecture — requiring convergence before firing, never a single trigger — stays.


What the risk module always includes

Non-negotiable on every build, regardless of tier:

def pre_trade_safety_check(symbol, state):
    if state.daily_pnl <= -state.daily_loss_limit:
        return False, "Daily loss limit reached"

    if state.daily_pnl >= state.daily_profit_target:
        return False, "Daily profit target reached"

    if state.concurrent_signals >= state.max_concurrent:
        return False, "Max concurrent positions"

    elapsed = time.time() - state.last_signal_time.get(symbol, 0)
    if elapsed < state.cooldown_seconds:
        return False, f"Cooldown active ({elapsed:.0f}s elapsed)"

    if state.daily_signal_count >= state.max_daily_signals:
        return False, "Daily signal cap reached"

    return True, "OK"
Enter fullscreen mode Exit fullscreen mode

Daily loss limit, daily profit target, concurrent position cap, per-symbol cooldown, daily signal cap. These are all configurable by client parameters. The structure itself is fixed.

The persistence layer:

def update_daily_pnl(conn, date, pnl_delta):
    conn.execute("""
        INSERT INTO daily_pnl (date, pnl)
        VALUES (?, ?)
        ON CONFLICT(date) DO UPDATE SET pnl = pnl + excluded.pnl
    """, (date, pnl_delta))
    conn.commit()

def get_daily_pnl(conn, date):
    row = conn.execute(
        "SELECT pnl FROM daily_pnl WHERE date = ?", (date,)
    ).fetchone()
    return row[0] if row else 0.0
Enter fullscreen mode Exit fullscreen mode

SQLite upsert on every trade close. If the process restarts at any point during the day, the daily P&L is accurate. Risk limits are never bypassed by a crash.


The three-tier service

I run this as a custom development service on Gumroad. Three tiers:

Starter — $200
Single-indicator logic, one asset, basic SL/TP, 5–7 day delivery. For traders who have a simple, clearly defined system. Good entry point if you want to test the process before a larger order.

Standard — $350
Multi-indicator signal engine, up to three assets, full risk management module (daily limits, position sizing, cooldowns), Telegram integration, SQLite logging. 7–10 days. This covers 80% of what people actually need.

Premium — $500
Any complexity. No asset limit, advanced logic, video walkthrough of the full codebase, 30-day support. For traders with complex multi-market systems who want everything documented thoroughly.

Every tier includes full annotated source code. Not compiled-only. You own the code, you understand the code, you can modify it yourself or bring it to any developer.

The process after purchase: you get a client intake form immediately. You describe your strategy in plain English — no coding knowledge required, just your rules. I review it within 24 hours, confirm scope in writing, and start building.


The questions I get most often from devs

"Can I just buy the code and modify it myself?"

If you want the architecture as a starting point, the Standard tier gives you a well-structured, commented codebase you can extend. A lot of developers order because they want to skip the scaffolding: the WebSocket connection handling, the indicator calculation library, the SQLite schema, the Telegram integration. All of that is already done. They add their signal logic on top.

"Can you add X feature after delivery?"

Bug fixes are covered in the support window. New features — adding an asset, adding an indicator, changing the strategy type — are new orders. I'm clear about this upfront so there are no misunderstandings at delivery.

"Do you do revenue share instead of flat fee?"

No. I charge for my time and expertise. Revenue share creates misaligned incentives — it puts me in a position of having financial exposure to a strategy's market performance, which I can't control. Flat fee, clean relationship.


One thing worth saying clearly

The 71% win rate people see on my Deriv bot article is real. It's also 24 trades, which is meaningful but not statistically conclusive. I say this in the article and I'll say it here.

What I can guarantee for custom orders is that the code is correct — it does exactly what was specified, tested, and documented. I can't guarantee that a client's strategy has a positive edge in the market. That part is on the strategy, not the implementation.

If you're not sure whether your strategy has an edge, trading it manually on demo for a few weeks before commissioning a bot is always the right call. I'd rather you have confidence in your logic before we build than discover problems post-delivery.


Where to find the service

It's on Gumroad: gumroad.com/preciousanusiem

Questions before purchasing, clarifications about whether your strategy is in scope, or anything else — I respond to everything.

📧 preciousanusiem.o.1@gmail.com
🔗 GitHub: github.com/PreciousAnusiem


If you've built something in this space — custom EAs, Python trading systems, Deriv bots — I'd genuinely like to hear about the engineering decisions you made. Drop it in the comments.

Top comments (0)