RETURN_TO_LOGS
SYS_DOCS: ONLINE
Algorithmic Trading

Building My First Trading Bot: From Idea to Automated Strategy

Aditya Pandit Sonwane
July 22, 2026
8 min read

TL;DR

  • Inspiration: Needed to eliminate emotional trading, manual charting fatigue, and late-night order execution delays.
  • Strategy: An EMA-based mean-reversion reversal model that dynamically calculates upper and lower trigger bands (EMA + Offset and EMA - Offset) to manage position flips.
  • Tech Stack: Pine Script v6, TradingView Webhooks, Node.js, TypeScript, Express, SQLite, React, and Binance USD-M Futures REST API in One-Way Mode.
  • Biggest Challenge Solved: Eliminating duplicate order stacking and position sizing mismatches by refactoring the backend position engine into a strict finite state machine (FSM) backed by an in-memory execution lock and post-trade validation.
  • Outcome: A fully production-ready, low-latency automated system with a real-time web telemetry dashboard and zero manual intervention required.
[SYS_TRANSITION]

Engineering Snapshot

Project: EMA Reversal Trading Bot

Goal: Automate an EMA-based trading strategy

Platform: TradingView + Binance USD-M Futures

Language: Pine Script v6 (TradingView) & TypeScript / Node.js (Backend Engine)

Exchange: Binance Futures

Timeframe: 15-minute / 1-hour chart bars

Indicators: Exponential Moving Average (EMA) with dynamic offset channels

Risk Management: One-Way Mode single net position enforcement, pre-trade open order resolution, execution lock, and post-trade validation kill switch

Current Status: Production Ready / Live Testing

[SYS_TRANSITION]

1. Introduction

Manual trading sounds simple on paper: wait for a price setup, enter a trade, and exit when target levels are reached. In practice, sticking to a mechanical system while watching live candles move in real time is one of the hardest things for a human trader to do.

During volatile market sessions, I found myself hesitating during valid entry signals, checking charts past midnight, and occasionally over-monitoring open positions. I realized that if a strategy is rule-based, a software program will always execute it with higher discipline, lower latency, and zero emotional bias.

My primary objective was to design a clean, automated system that links TradingView alerts directly to Binance Futures execution. I wanted the system to handle single-order position reversals atomically while guaranteeing that my account never holds multiple positions or stacked orders.

This blog covers the entire journey: from strategy design and Pine Script implementation to backend execution logic, system architecture, challenges encountered, and key takeaways.

[SYS_TRANSITION]

2. Background

What is Algorithmic Trading?

Algorithmic trading is the process of executing financial orders using automated, computer-coded rules. Instead of placing trades manually through a user interface, an algorithm continuously monitors market data, evaluates predefined math or indicator criteria, and submits orders directly to exchange APIs.

Why TradingView?

TradingView is one of the most powerful charting platforms available. Its scripting engine, Pine Script, allows developers to prototype and backtest quantitative ideas quickly without building custom chart rendering engines. Using TradingView's webhook alert system allows the charting engine to handle indicator calculations while delegating order execution to a custom web server.

Why Binance?

Binance Futures is one of the highest-liquidity crypto derivatives platforms in the world. It provides comprehensive REST and WebSocket APIs for account management, position tracking, and order placement. Their USD-M Futures contract market offers high throughput and low execution latency, making it an ideal venue for automated derivatives trading.

[SYS_TRANSITION]

3. Defining the Problem

Before writing a single line of code, I mapped out the specific operational problems I wanted to solve:

  • Emotional Decision-Making: Second-guessing entry signals or prematurely modifying target levels during live candles.
  • Missed Signals: Unable to monitor charts 24/7, leading to missed trades during overnight sessions.
  • Execution Latency: Time lost manually opening an exchange interface, calculating contract sizing, and placing orders.
  • Position Management Mismatches: Ensuring that position reversals (flipping from Short to Long or vice versa) happen atomically without leaving orphaned orders or dual-sided exposure.
[SYS_TRANSITION]

4. Planning the Strategy

Initial Idea

The baseline concept was a mean-reversion channel strategy. Price tends to fluctuate around an exponential moving average. When price stretches too far away from the baseline, it creates an overextended channel condition. The goal was to enter positions at these boundary triggers and flip positions when price reaches the opposite channel level.

Trading Logic

  • Baseline Calculation: Calculate a dynamic EMA of length N (e.g., 20 period).
  • Upper Trigger: EMA + Offset (Calculated as Points or Percentage).
  • Lower Trigger: EMA - Offset (Calculated as Points or Percentage).
  • Position Rules: The account must always be in exactly one of three states:
  • No Position (Only prior to the first trade)
  • Long 0.5 contracts
  • Short 0.5 contracts
  • Reversal Rule: When holding a Short of 0.5 contracts and price crosses the Lower Trigger, submit a single BUY order of 1.0 contracts. This closes the 0.5 Short and opens a 0.5 Long in a single market order.

Flowchart:

Trading Signal (TradingView Alert) ↓ Webhook Handler (Backend API) ↓ Check Lock & Fetch Binance State ↓ Evaluate State Machine & Position Rules ↓ Submit Market Order (Binance REST API) ↓ Poll Order Status until FILLED ↓ Post-Trade Position Validation ↓ Update Database Log & Telemetry Dashboard

[SYS_TRANSITION]

5. System Architecture

Trading Bot Strategy Architecture & Telemetry
Trading Bot Strategy Architecture & Telemetry

The architecture separates chart calculations from order execution:

TradingView Chart ↓ Pine Script v6 Strategy ↓ Alert Event (alert.freq_once_per_bar_close) ↓ HTTP POST Webhook Payload ↓ Node.js / Express Web Server ↓ Signal Validator & Risk Manager ↓ Position Manager (Finite State Machine) ↓ Binance Futures REST API ↓ Order Execution ↓ SQLite Database Audit Log & React Web Dashboard

[SYS_TRANSITION]

6. Technologies Used

| Component | Technology | |-----------|------------| | Strategy | Pine Script v6 | | Charts | TradingView | | Exchange | Binance USD-M Futures | | Language | TypeScript / Node.js | | Hosting | Docker / Self-Hosted VPS | | Database | SQLite3 |

[SYS_TRANSITION]

7. Strategy Explanation

Indicator Selection

The Exponential Moving Average (EMA) was selected because it gives higher weight to recent price action compared to a Simple Moving Average (SMA). This makes the baseline responsive to recent structural shifts while providing a clean center line for mean-reversion calculations.

Entry Logic

The entry logic is straightforward:

  1. Initial Entry: When no position exists, price crossing above EMA + Offset triggers a SELL market order of 0.5 contracts (Short). Price crossing below EMA - Offset triggers a BUY market order of 0.5 contracts (Long).
  2. Position Reversal: When holding Short 0.5 and price crosses EMA - Offset, a single BUY market order of 1.0 contracts is placed.

Pseudo Code:

text
upperBand = EMA + Offset
lowerBand = EMA - Offset

if currentState == NO_POSITION:
    if price crosses upperBand:
        submit SELL 0.5 -> State becomes SHORT 0.5
    else if price crosses lowerBand:
        submit BUY 0.5 -> State becomes LONG 0.5

else if currentState == SHORT:
    if price crosses lowerBand:
        submit BUY 1.0 -> State becomes LONG 0.5

else if currentState == LONG:
    if price crosses upperBand:
        submit SELL 1.0 -> State becomes SHORT 0.5

Exit & Reversal Logic

There are no static take-profit orders placed on the exchange order book. Instead, the opposite band crossover acts as the exit and reversal trigger simultaneously.

Position Management

To prevent pyramiding or scale-in errors, the system enforces a strict single net position. Duplicate signals in the direction of the current position are automatically filtered out.

Risk Management

  • Binance One-Way Mode: Ensures that opposite market orders reduce and reverse the existing position rather than creating dual Long/Short legs.
  • Execution Lock: Locks the trading engine while an order is processing to prevent race conditions.
  • Open Order Polling: Verifies that no stale open orders exist on Binance before placing a new order.
  • Post-Trade Validation: Immediately after order execution, the backend fetches position risk from Binance. If the resulting size does not equal 0.5, the system halts trading and triggers an Emergency Kill Switch.
[SYS_TRANSITION]

8. Development Process

Building this system took multiple iterative steps to move from simple scripts to a robust production infrastructure.

Version 1: Basic Pine Script Alert & Simple Express Listener

  • Goal: Connect TradingView webhooks to a basic server script.
  • Problem: TradingView sent duplicate alert triggers on volatility spikes, resulting in multiple order calls sent to Binance.
  • Solution: Implemented signal hash fingerprinting and an in-memory cache in SQLite to drop duplicate alert IDs.

Version 2: Multi-Order Flips in Hedge Mode

  • Goal: Execute position reversals.
  • Problem: Because Binance was in Hedge Mode by default, submitting a BUY order while holding a Short created dual Long and Short positions simultaneously.
  • Solution: Configured the backend to set Binance to One-Way Mode (dualSidePosition: false) on startup, enabling single-order 1.0 quantity market reversals.

Version 3: State Machine & Post-Trade Validation

  • Goal: Ensure absolute system reliability during exchange API latency or market gaps.
  • Problem: Market orders occasionally took a few hundred milliseconds to transition from NEW to FILLED, leading to race conditions if subsequent webhooks arrived.
  • Solution: Refactored the position engine into a Finite State Machine with explicit order status polling (getOrderStatus) and post-trade validation checks.
[SYS_TRANSITION]

9. Code Walkthrough

Pine Script v6 Initialization & Band Calculation

The script defines the inputs and calculates the dynamic upper and lower bands:

pinescript
//@version=6
strategy(
     title="EMA Mean-Reversion Reversal Strategy [Binance Futures]",
     shorttitle="EMA Reversal Bot",
     overlay=true,
     initial_capital=1000,
     default_qty_type=strategy.fixed,
     default_qty_value=0.5,
     pyramiding=0,
     commission_type=strategy.commission.percent,
     commission_value=0.04
 )

int emaLength = input.int(20, title="EMA Length")
string offsetType = input.string("Percentage", title="Offset Calculation Method", options=["Points", "Percentage"])
float offsetVal = input.float(1.0, title="Offset Value")
float basePositionSize = input.float(0.5, title="Base Position Size")

float emaVal = ta.ema(close, emaLength)
float offsetDist = offsetType == "Points" ? offsetVal : emaVal * (offsetVal / 100.0)

float upperBand = emaVal + offsetDist
float lowerBand = emaVal - offsetDist

Signal Generation & JSON Webhook Payload

Cross events trigger the custom JSON alert payload:

pinescript
bool crossAboveUpper = ta.crossover(close, upperBand)
bool crossBelowLower = ta.crossunder(close, lowerBand)

if crossAboveUpper
    strategy.entry("ShortReversal", strategy.short, qty=basePositionSize, comment="SELL_REVERSAL")

if crossBelowLower
    strategy.entry("LongReversal", strategy.long, qty=basePositionSize, comment="BUY_REVERSAL")

getAlertJson(string signalType) =>
    '{"symbol":"' + syminfo.ticker + '","signal":"' + signalType + '","price":' + str.tostring(close) + ',"ema":' + str.tostring(emaVal) + ',"upperTrigger":' + str.tostring(upperBand) + ',"lowerTrigger":' + str.tostring(lowerBand) + ',"timestamp":' + str.tostring(timenow) + ',"secret":"' + webhookSecret + '"}'

if crossAboveUpper
    alert(getAlertJson("SELL_REVERSAL"), alert.freq_once_per_bar_close)

if crossBelowLower
    alert(getAlertJson("BUY_REVERSAL"), alert.freq_once_per_bar_close)

Backend Position State Machine Execution

In Node.js, PositionManager.ts processes incoming webhooks safely:

typescript
// Enforce execution lock
if (this.isProcessing) {
  return { success: false, message: 'Order lock is active. Signal ignored.' };
}
this.isProcessing = true;

try {
  // 1. Pre-trade synchronization with Binance
  await this.syncStateWithExchange(targetSymbol);

  // 2. State Machine duplicate signal filtering
  if (isBuySignal && this.currentPosition === 'LONG') {
    return { success: true, message: 'Long position already active. Signal ignored.' };
  }

  // 3. Calculate quantity (0.5 for initial entry, 1.0 for reversal)
  const baseSize = config.strategy.basePositionSize || 0.5;
  const orderQty = (this.currentPosition !== 'NO_POSITION') ? baseSize * 2 : baseSize;
  const orderSide = isBuySignal ? 'BUY' : 'SELL';

  // 4. Place single MARKET order & poll until FILLED
  let order = await binanceClient.createMarketOrder(this.activeSymbol, orderSide, orderQty, false);
  await this.pollOrderStatusUntilFilled(order.orderId);

  // 5. Post-trade validation
  await this.syncStateWithExchange(this.activeSymbol);
  if (Math.abs(this.currentQty - baseSize) > 0.0001) {
    riskManager.setEmergencyStop(true);
    throw new Error('Post-trade size validation failed! Emergency stop activated.');
  }
} finally {
  this.isProcessing = false;
}
[SYS_TRANSITION]

10. Backtesting

The strategy was tested using historical futures data in TradingView across multiple liquid cryptocurrency pairs.

  • Market Pairs: BTCUSDT, SOLUSDT, ETHUSDT
  • Timeframe: 15-minute and 1-hour candles
  • Starting Capital: $1,000 USDT
  • Commission: 0.04% (Taker fee schedule)
  • Leverage: 5x
[SYS_TRANSITION]

11. Results

Performance metrics vary by market condition:

  • Trending Markets: Extended single-direction trends can lead to drawdowns if price continues past the band before reverting.
  • Ranging / Mean-Reverting Markets: High win rate and strong profit factors as price moves consistently between the upper and lower channel boundaries.
  • Execution Consistency: Single-order reversals in One-Way Mode executed cleanly with zero orphaned positions during backtesting and paper trading runs.
[SYS_TRANSITION]

12. Challenges Faced

1. Binance Dual Position (Hedge Mode) Conflict

  • Challenge: Submitting an opposite order in Hedge Mode resulted in two active positions (Long and Short) instead of closing the existing one.
  • Solution: Added automatic API configuration during server startup to set Binance account position mode to One-Way Mode (dualSidePosition: false).

2. Duplicate Alert Triggers

  • Challenge: Network retries or rapid bar updates occasionally sent duplicate alert payloads for the same crossing bar.
  • Solution: Implemented dual-layer deduplication: an in-memory hash cache in SQLite for signal fingerprints and a strict position state check in the backend Finite State Machine.

3. Asynchronous SQLite Database Queries

  • Challenge: An early implementation of the duplicate signal query called an asynchronous database method inside a synchronous validation function, causing duplicate checks to evaluate incorrectly.
  • Solution: Refactored the database logger to pre-load a synchronous Set cache of signal hashes upon application startup.
[SYS_TRANSITION]

13. Lessons Learned

  • Separation of Concerns: Keeping chart calculations on TradingView and position logic on the backend makes the system modular and far easier to debug.
  • Always Verify Exchange State: Never rely strictly on local state variables. Always synchronize with the exchange REST API prior to placing new orders.
  • One-Way Mode Simplifies Reversals: Reversing a position with a single order of size 2 * baseSize in One-Way Mode reduces fee latency and eliminates dual-position management complexity.
[SYS_TRANSITION]

14. Future Improvements

  • Multi-Timeframe Trend Filter: Adding a higher timeframe EMA filter (e.g., 200 EMA) to only take Longs above the trend line and Shorts below it.
  • Dynamic Volatility Scaling: Scaling offset percentages automatically using ATR (Average True Range) to adapt to changing volatility regimes.
  • Telegram Notification Bot: Sending instant trade execution reports and PnL summaries directly to a Telegram channel.
  • Multi-Exchange Adapter: Abstracting the exchange client layer to support Bybit and OKX alongside Binance.
[SYS_TRANSITION]

15. Resources

[SYS_TRANSITION]

16. Conclusion

Building this trading bot was a rewarding engineering exercise. It bridged quantitative strategy design in Pine Script with backend systems engineering in TypeScript and Node.js.

The system is now fully modular, thoroughly tested with automated Jest suites, and equipped with a real-time web telemetry dashboard. Automating the strategy removed the friction of manual trade execution and created a reliable, rule-based infrastructure.

[SYS_TRANSITION]

Key Takeaways

  • Technical Lesson: Always validate exchange state post-execution rather than assuming market orders fill instantaneously without slip or API latency.
  • Trading Lesson: Strategy simplicity and strict position limits are far more effective than overly complex, indicator-heavy setups.
  • Programming Lesson: Designing state logic around a formal Finite State Machine (FSM) eliminates entire classes of edge-case bugs in financial software.
  • Advice for Beginners: Start with testnet APIs, write automated unit tests for your order manager, and never deploy live funds until your system handles error states gracefully.
[SYS_TRANSITION]

Final Thoughts

Building an automated trading bot from scratch teaches you far more than simply running someone else's pre-made indicator. It forces you to think deeply about system reliability, edge-case safety, API error handling, and exchange mechanics.

If you are interested in algorithmic trading, start small: write a simple Pine Script strategy, build a basic webhook receiver, test it on a testnet, and iterate. The engineering principles you learn along the way are invaluable.

Aditya Pandit Sonwane
Aditya Pandit Sonwane

Systems & Robotics Engineer. Developing autonomous mobile platforms, configuring ROS2 EKF nodes, writing real-time CUDA perception pipelines, and embedded microcontrollers logic.