Building a Python Algorithmic Trading Platform with TradingView, Bybit API and WebSocket
DEV Community

Building a Python Algorithmic Trading Platform with TradingView, Bybit API and WebSocket

Introduction

Most algorithmic trading projects begin with a deceptively simple idea. Connect TradingView to an exchange API, receive webhook signals, execute market orders, and let automation handle the rest. On paper, the architecture seems almost trivial:

TradingView
โ”‚
Webhook
โ”‚
Python Script
โ”‚
Exchange API

After all, sending a POST request and placing a market order only takes a few lines of Python. That assumption lasted exactly until the first real trading scenarios appeared. The moment open positions had to survive an application restart, partial profits needed to be tracked correctly, stop losses had to move automatically to break even, and live market prices started arriving several times per second, the project stopped looking like a "trading bot." It became a distributed software system with multiple independent components that had to cooperate reliably under constantly changing market conditions.

Over the past several months I've been building a modular algorithmic trading platform in Python. The original goal was never to create another "buy and sell" script. Instead, I wanted an architecture that could evolve over time without constantly rewriting core components every time a new feature appeared. This article describes the engineering decisions behind that architecture, the problems that emerged during development, and why separating responsibilities between components made the system significantly easier to maintain.

Why Most Trading Bots Eventually Become Unmaintainable

Key idea: A trading bot becomes difficult to maintain when every feature is implemented inside a single execution flow.

One pattern appears repeatedly in open-source trading bots. Everything happens inside one large function:

  • A webhook arrives.
  • The exchange API is called.
  • The position is updated.
  • Risk checks are performed.
  • Analytics are calculated.
  • Notifications are sent.

Eventually thousands of lines of business logic end up sharing the same execution flow. Initially this approach feels productive because features can be added quickly. Later, every modification becomes risky:

  • Adding a trailing stop unexpectedly breaks take-profit logic.
  • Implementing futures trading affects spot trading.
  • Introducing Telegram controls changes execution behaviour.

Instead of building another bot, I decided to build a platform.

From a Trading Bot to a Trading Platform

TradingView
โ”‚
FastAPI Webhook
โ”‚
Trade Execution Engine
โ”‚
Risk Management
โ”‚
Position Manager
    โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
    โ”‚                 โ”‚
Spot Execution   Futures Execution
    โ”‚                 โ”‚
    โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
             โ”‚
         Bybit API
             โ”‚
     Analytics Engine
             โ”‚
   Telegram Control Panel

Each layer has a single responsibility:

  • Webhook validates requests.
  • Trade Execution Engine interprets signals.
  • Risk Manager applies trading rules.
  • Position Manager owns the lifecycle of positions.
  • Execution Layer communicates with the exchange.
  • Analytics processes completed trades.
  • Telegram provides operational control.

This separation dramatically reduced complexity as the project evolved.

Why the Webhook Should Never Execute Orders Directly

Many tutorials show something similar to this:

@app.post("/webhook")
def webhook(signal):
    client.place_order(signal)

While this is sufficient for a demo, production systems quickly expose its limitations. Questions appear immediately:

  • What if TradingView sends the same webhook twice?
  • What if the exchange rejects the order?
  • What if another position is already open?
  • What if the signal arrives after market conditions have changed?

Instead, the webhook performs only three responsibilities:

  1. Validate incoming requests.
  2. Verify authentication and secrets.
  3. Forward a normalized signal to the Trade Execution Engine.

Business logic belongs elsewhere.

Designing the Trade Execution Engine

The Trade Execution Engine became the heart of the platform. Its responsibility is intentionally narrow. It does not calculate indicators. It does not generate analytics. It does not manage Telegram. It simply transforms validated signals into trading actions.

Typical actions include:

  • BUY_SPOT
  • SELL_FUTURES
  • CLOSE_POSITION

Before dispatching an order, the engine checks:

  • Is the trading pair enabled?
  • Is there already an open position?
  • Has this signal already been processed?
  • Does the current application state allow execution?

Only then does the execution layer communicate with the exchange.

About the Project

The examples shown throughout this series are taken from a personal algorithmic trading platform that I've been building and refining over the past several months. The project continues to evolve as new engineering challenges appear during development.

Additional information about the platform is available here: https://py-dev.top/application-software/bybit-signal-trading-bot

What's Next

The next article in this series will explore the architecture of the Trade Execution Engine in much greater depth, including signal routing, duplicate protection, state awareness, and execution flow.

Comments

No comments yet. Start the discussion.