Building MyAlgoBot: A Multi-Market Algorithmic Trading System with Alpaca

By Ramnesh Kumar Sahu

This content is for educational and informational purposes only and should not be construed as investment advice, a recommendation, or an offer to buy or sell any securities or cryptocurrencies. Any strategies discussed are illustrative only and may not be suitable for all investors. This article reflects the experience of an individual user, is not representative of all customers, and should not be considered an endorsement or guarantee of future performance. The views and opinions expressed are those of the author and do not reflect or represent the views and opinions of Alpaca. Alpaca does not recommend any specific securities or investment strategies.The author was not compensated for this content but did receive nominal promotional items from Alpaca.

Background: Why I Built This

I am a B.Tech Computer Science (AI/ML) student, and alongside my coursework I co-founded an early-stage deep-tech startup where I work on systems architecture and embedded software. Markets and machine learning felt like two separate interests, but I started asking a simple question: could I apply the same engineering discipline I use for building production systems to something as complex as live markets?

That question turned into MyAlgoBot. This multi-market algorithmic trading system monitors and (in paper/testnet form) trades across US equities, Indian equities, and crypto simultaneously, combining three classic technical strategies into a single voting signal engine, all running unattended on a cloud server.

I want to be upfront about what this article is and isn't. It is a walkthrough of how I designed, built, and deployed a personal trading system over a short, intense build sprint, and what I learned along the way. Architecture decisions, integration headaches, and the parts I'd redesign if I started over. It is not a claim that this system is profitable, that its signals are reliable, or that anyone should replicate its logic and expect similar outcomes. I tested everything described here in a paper-trading environment first. I found this approach essential for validating infrastructure logic before managing market data.

What Is MyAlgoBot?

At a high level, MyAlgoBot is a single Python process that:

  1. Pulls recent price data for a watchlist of instruments across three markets on a fixed interval
  2. Runs three independent technical strategies against that data
  3. Combines their outputs into one signal using a simple voting rule
  4. Passes any resulting signal through a risk-management layer (position sizing, stop-loss, and take-profit)
  5. Submits the order 
  6. Reports every action to a Telegram channel in real time

I designed my implementation of the system to run continuously and unattended as part of my personal testing and development process. This meant deployment and reliability mattered just as much as the strategy logic.

System Architecture

Why Alpaca Became the Anchor of the System

I started building on Alpaca specifically because I wanted a market where I could fully validate a strategy before touching anything else. A few features made it a good fit for my project:

  • Paper trading that mirrors live execution. The same alpaca-py interface, the same order types, and the same account/position objects. These route to a simulated environment. That meant I could develop against the real API surface from day one instead of writing a mock layer I'd have to throw away later.
  • Clean, well-documented Python SDK. Between historical bars, account state, and order submission, I could get a working data pipeline running quickly without fighting the API itself.
  • No forced complexity. The SDK simplified many common development tasks, allowing me to focus on building the trading system.

Because of this, I used Alpaca to validate the signal engine before I trusted it enough to wire up the other two brokers.

Pulling Data

from alpaca.data.historical import StockHistoricalDataClient
from alpaca.data.requests import StockBarsRequest
from alpaca.data.timeframe import TimeFrame
from datetime import datetime, timedelta

class AlpacaBroker:
    def __init__(self, api_key, secret):
        self.data = StockHistoricalDataClient(api_key, secret)

    def get_data(self, symbol, limit=100):
        request = StockBarsRequest(
            symbol_or_symbols=symbol,
            timeframe=TimeFrame.Minute,
            start=datetime.now() - timedelta(hours=3),
            limit=limit
        )
        bars = self.data.get_stock_bars(request)
        return bars.df.reset_index()

Submitting Orders

from alpaca.trading.client import TradingClient
from alpaca.trading.requests import MarketOrderRequest
from alpaca.trading.enums import OrderSide, TimeInForce

class AlpacaExecution:
    def __init__(self, api_key, secret):
        self.trading = TradingClient(api_key, secret, paper=True)

    def place_order(self, symbol, qty, side):
        order = self.trading.submit_order(
            MarketOrderRequest(
                symbol=symbol,
                qty=qty,
                side=OrderSide.BUY if side == "buy" else OrderSide.SELL,
                time_in_force=TimeInForce.GTC
            )
        )
        return order

    def close_position(self, symbol):
        self.trading.close_position(symbol)

Keeping the broker interface this limited turned out to matter a lot later. It made it much easier to write parallel ZerodhaBroker and BinanceBroker classes that exposed the same shape (get_data, place_order, close_position, and get_balance) even though the underlying APIs are completely different.

Going Multi-Market: Why Did I Add Zerodha and Binance

Once I validated the signal engine and risk layer on Alpaca in paper mode, I wanted to test the same architecture against markets with very different structure and hours. Indian equities via Zerodha's Kite Connect, and crypto via Binance's testnet.

This wasn't about chasing more opportunities. It was a design test. If I built the signal engine and risk manager correctly, they should be broker-agnostic. Swapping in a new market should only mean writing a new broker adapter, not touching the strategy logic. That constraint shaped a lot of my architecture decisions early on.

Market

Broker

Hours (IST)

What I used it to test

US Equities

Alpaca (paper)

7:00 PM – 1:30 AM

Initial paper-trading validation

Indian Equities

Zerodha Kite Connect

9:15 AM – 3:30 PM

Regulatory constraints (static IP requirement, intraday square-off)

Crypto

Binance (testnet)

24/7

Always-on execution, funding-rate-free spot logic 

A few things I hadn't anticipated became real engineering problems:

  • Zerodha requires a daily re-authentication flow. The access token expires at midnight, so any always-on deployment needs a way to refresh it every morning before the market opens.
  • India's regulator now requires API orders to originate from a registered static IP. This meant the cloud deployment had to reserve and register a static IP before I could route any live orders through Kite Connect.
  • Crypto exchanges enforce geo-restrictions at the infrastructure level. Binance entirely blocked my first cloud region, which forced me to rethink where crypto execution should run versus where the rest of the system lives.

None of this is a criticism of any platform. It's just a reminder that "multi-market" isn't a strategy decision, it's an infrastructure decision. It surfaces itself the moment you try to deploy rather than just backtest.

The Signal Engine: Three Strategies, One Vote

I didn't want to rely on a single indicator flipping a coin. Instead, I implemented three independent, well-known technical strategies and required at least two of them to agree before a signal was actionable.

1. EMA Crossover with RSI filter: A 9-period EMA crossing above/below a 21-period EMA, filtered by RSI to avoid firing in clearly overbought/oversold conditions.

2. Mean Reversion via Bollinger Bands: Price touching the lower band with RSI below ~35 as a long signal; the inverse for short.

3. Momentum via MACD: A MACD line crossing its signal line, confirmed by histogram direction.

def get_combined_signal(df):
    ema_signal = ema_crossover_signal(df)
    mr_signal = mean_reversion_signal(df)
    mom_signal = momentum_signal(df)

    votes = [ema_signal, mr_signal, mom_signal]

    if votes.count("BUY") >= 2:
        return "BUY"
    elif votes.count("SHORT") >= 2:
        return "SHORT"
    elif votes.count("SELL") >= 2:
        return "SELL"
    elif votes.count("COVER") >= 2:
        return "COVER"
    return "HOLD"

This "2-of-3 vote" design was a deliberate attempt to reduce single-indicator whipsaw. In my own testing, it meant far fewer trades overall. Most cycles resolve to HOLD. The signals that did fire tended to have more than one form of technical confirmation behind them. This is an observation of system behavior in my specific test environment, not a prediction of results. I want to be careful here: this is an observation about how the system behaved in my own testing, not a claim about expected performance for anyone using a similar approach.

Risk Management Layer

Every signal that passes the voting stage still has to clear a separate risk layer before an order is submitted:

class RiskManager:
    def __init__(self, total_capital, max_drawdown=0.10):
        self.total_capital = total_capital
        self.peak_capital = total_capital
        self.current_capital = total_capital
        self.max_drawdown = max_drawdown
        self.trading_allowed = True

    def position_size(self, risk_pct=0.05):
        return self.current_capital * risk_pct

    def check_drawdown(self):
        drawdown = (self.peak_capital - self.current_capital) / self.peak_capital
        if drawdown >= self.max_drawdown:
            self.trading_allowed = False
        return self.trading_allowed

Fixed rules on top of this: a 3% stop-loss and 9% take-profit on every position (roughly a 1:3 risk-reward skew), a hard cap on capital deployed per trade, and. For the Indian equities leg specifically. An automatic square-off routine that flattens all intraday positions ahead of Zerodha's 3:20 PM auto square-off cutoff, since MIS (intraday) products there cannot be held overnight.

I consider this a critical component of the build. Getting the strategy signal "right" mattered a lot less to system stability than making sure nothing could ever trade past its risk limit, silently double-order, or hold a leveraged intraday position it wasn't allowed to carry overnight.

Deployment: Making It Actually Run Unattended

A strategy that only works when you're watching a terminal isn't a system. It's a demo. I spent as much engineering time getting MyAlgoBot to run continuously as I did on the strategy logic itself.

Stack:

  • Python 3.11 on a Google Cloud e2-micro VM (Debian 12)
  • systemd service definition with Restart=always for automatic recovery from crashes or reboots
  • A reserved static IP (required for the Zerodha integration under current exchange rules)
  • Telegram Bot API for real-time trade and error notifications
  • GitHub (private) for version control, with credentials kept out of the repo via .gitignore
[Unit]
Description=MyAlgoBot Trading Bot
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
WorkingDirectory=/home/user/algo_system
ExecStartPre=/bin/sleep 30
ExecStart=/usr/bin/python3 main.py
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target

I added the sleep 30 before start and the explicit wait on network-online.target after the service kept crash-looping on boot. It was starting before the VM's network stack was actually ready to make outbound API calls. A small fix, but the kind you only discover by deploying, not by reading documentation.

I push every state change, a signal firing, an order filling, a stop-loss triggering, or a drawdown limit being hit to a Telegram channel. That turned out to be more valuable than any dashboard I could have built in the same amount of time. It's push-based, works from a phone, and gives a running audit log for free.

What I'd Do Differently

  • Build the risk layer first, strategy second. I built strategy logic before I fully fleshed out the risk manager. This meant I had to retrofit position sizing and drawdown limits into code that wasn't designed for it.
  • Separate "detect" from "execute" earlier. Right now, signal generation and order execution live close together in the same loop. In hindsight, I would structure this closer to an agent/execution-boundary pattern. A decision layer proposes an action and a separate, simpler layer validates and executes it. This would make the system easier to audit and safer to extend.
  • Don't assume market data is instantly fresh. One of the more frustrating bugs I hit was a price appearing "stuck" because I was reusing the last closed candle instead of pulling a live quote. This serves as a reminder to be explicit about which price a system is actually acting on.
  • Test broker adapters against real geo/regulatory constraints earlier, not after deployment. The Zerodha static-IP requirement and the Binance region block were both things I discovered mid-build rather than during design.

What's Next

A few directions I'm actively exploring:

Exploring Alpaca's MCP Server. I mentioned the decision/execution separation above. This is essentially what I've seen in Alpaca's own MCP-based examples. A policy and execution boundary sitting between an agent's reasoning and the actual order submission, with approval gates in between. I'd like to rebuild MyAlgoBot's execution layer around that pattern. A research/signal layer that proposes trades, and a strictly rule-based layer (with no model in the loop) that validates and submits them. It maps cleanly onto the risk-manager separation I already have, and it would make the system's decision trail far easier to audit.

Backtesting across more instruments and longer windows. The next step is walk-forward testing across a broader universe before drawing any conclusions about the strategy logic itself.

Open-sourcing the broker-adapter layer. The get_data, place_order, close_position, and get_balance interface pattern lets me plug in Alpaca, Zerodha, and Binance behind one signal engine. I feel this is worth sharing as a lightweight reference for others exploring multi-broker paper-trading systems.

Expanding beyond spot logic, once the current system has a longer, more rigorously tested track record in paper trading.

Conclusion

This project sits at the intersection of the things I actually care about. Systems architecture, applied engineering discipline, and markets. Building it end to end, from strategy logic to a 24/7 cloud deployment, taught me more about production engineering than any single classroom project has.Alpaca's paper trading environment provided a convenient way for me to test the infrastructure before working with live trading environments..

If you're a student or early-career builder thinking about a similar project: start in paper trading, build the risk layer before you trust the strategy, and expect the deployment problems to teach you more than the strategy problems will.

Resources

If you want to start building your own systematic trading system, here are the resources I found most useful:

About the Author

Ramnesh Kumar Sahu

Ramnesh Kumar Sahu is a B.Tech Computer Science (AI/ML) student and co-founder of an early-stage deep-tech startup, with a focus on systems architecture and embedded software. MyAlgoBot is a personal project built to apply production-engineering discipline to algorithmic trading.


*The Paper Trading API is offered by AlpacaDB, Inc. and does not require real money or permit a user to transact in real securities in the market. Providing use of the Paper Trading API is not an offer or solicitation to buy or sell securities, securities derivative or futures products of any kind, or any type of trading or investment advice, recommendation or strategy, given or in any manner endorsed by AlpacaDB, Inc. or any AlpacaDB, Inc. affiliate and the information made available through the Paper Trading API is not an offer or solicitation of any kind in any jurisdiction where AlpacaDB, Inc. or any AlpacaDB, Inc. affiliate (collectively, “Alpaca”) is not authorized to do business.

Alpaca and the referenced companies are unaffiliated and are each responsible for their own liabilities.

This article is for educational and informational purposes only and should not be construed as investment advice, a recommendation, or an offer to buy or sell any security or cryptocurrency. The views expressed are those of the author and do not necessarily reflect those of Alpaca. Alpaca does not recommend any specific securities, cryptocurrencies, or investment strategies. Examples provided are illustrative only and are not indicative of future results.

Automated and algorithmic trading strategies involve additional risks, including software defects, connectivity failures, execution delays, and market volatility. Such systems may not perform as intended and should be thoroughly tested before use.

Any trading strategies, technical indicators, or code examples are provided solely for educational purposes and should not be interpreted as investment advice or a recommendation or endorsement of any particular security or investment strategy.

Alpaca does not prepare, edit, endorse, or guarantee the accuracy of third-party content and is not responsible for content available through third-party sources.

All investments involve risk, including the possible loss of principal. Past performance does not guarantee future results. No investment strategy can guarantee a profit or achieve its intended objectives. Diversification does not ensure a profit or protect against loss. Investors should carefully consider their investment objectives, risks, charges, and expenses before investing.

Cryptocurrency is highly speculative in nature, involves a high degree of risks, such as volatile market price swings, market manipulation, flash crashes, and cybersecurity risks. Cryptocurrency regulations are continuously evolving, and it is your responsibility to understand and abide by them. Cryptocurrency trading can lead to large, immediate and permanent loss of financial value. You should have appropriate knowledge and experience before engaging in cryptocurrency trading. Cryptocurrencies are not stocks and your cryptocurrency investments are not protected by either FDIC or SIPC. For additional information, please click read Crypto Risk Disclosures. 

Securities brokerage services are provided by Alpaca Securities LLC ("Alpaca Securities"), member FINRA/SIPC, a wholly-owned subsidiary of AlpacaDB, Inc. Technology and services are offered by AlpacaDB, Inc.

Cryptocurrency services are made available by Alpaca Crypto LLC ("Alpaca Crypto"), a FinCEN registered money services business (NMLS # 2160858), and a wholly-owned subsidiary of AlpacaDB, Inc. Alpaca Crypto is not a member of SIPC or FINRA. Cryptocurrencies are not stocks and your cryptocurrency investments are not protected by either FDIC or SIPC. Please see the Disclosure Library for more information.

This is not an offer, solicitation of an offer, or advice to buy or sell securities or cryptocurrencies or open a brokerage account or cryptocurrency account in any jurisdiction where Alpaca Securities or Alpaca Crypto, respectively, are not registered or licensed, as applicable.