Design patterns are reusable solutions to common problems in software development. In this post, I’ll explain how I used the Strategy and Factory patterns in my trading server to easily switch between broker APIs like Alpaca and BingX, and how adding new brokers is made simple.


The Problem

Imagine you’re building an app that interacts with multiple trading platforms (brokers). Each platform has its own API, but they all perform similar tasks: placing orders, fetching balances, and closing positions. We need a flexible way to switch between brokers without rewriting the core app logic.

This is where the Strategy and Factory patterns help.


What are the Strategy and Factory Patterns?

Strategy Pattern

The Strategy Pattern lets you define a family of algorithms, each one encapsulated, and makes them interchangeable. In our case, each broker (e.g., Alpaca, BingX) is a different strategy for trading operations.

Factory Pattern

The Factory Pattern provides a way to create objects (like broker APIs) without specifying the exact class. It allows us to decide which broker to use based on runtime conditions, making it easy to add new brokers later.


How I Implemented These Patterns in the Trading App

We’ll break this down into a few steps, starting with the broker interface.


1. The Broker Interface (Strategy)

We define a generic broker interface that all broker classes must implement. It includes methods like create_order()get_balance(), and close_position().

from abc import ABC, abstractmethod

class Broker(ABC):
    @abstractmethod
    def create_order(self, symbol: str, quantity: float, side: str):
        pass

    @abstractmethod
    def get_balance(self):
        pass

    @abstractmethod
    def close_position(self, symbol: str, quantity: float):
        pass

2. Concrete Broker Implementations

We then implement this interface for Alpaca and BingX, each with its own logic for the operations.

Alpaca API:

class AlpacaApi(Broker):
    def create_order(self, symbol: str, quantity: float, side: str):
        # Alpaca-specific code for creating an order
        pass

    def get_balance(self):
        # Alpaca-specific code for fetching balance
        pass

    def close_position(self, symbol: str, quantity: float):
        # Alpaca-specific code for closing a position
        pass

BingX API:

class BingXApi(Broker):
    def create_order(self, symbol: str, quantity: float, side: str):
        # BingX-specific code for creating an order
        pass

    def get_balance(self):
        # BingX-specific code for fetching balance
        pass

    def close_position(self, symbol: str, quantity: float):
        # BingX-specific code for closing a position
        pass

3. The Factory (Factory Pattern)

The Factory method decides which broker to use based on the broker’s name. This allows the app to easily switch brokers at runtime.

def get_broker(broker_name: str) -> Broker:
    if broker_name == "alpaca":
        return AlpacaApi()
    elif broker_name == "bingx":
        return BingXApi()
    else:
        raise ValueError(f"Unsupported broker: {broker_name}")

4. Usage Example

Here’s how the app uses the broker. It decides which broker to use at runtime, making the code flexible and easy to extend with new brokers.

def main():
    broker_name = "alpaca"  # This can change dynamically based on user input
    broker = get_broker(broker_name)

    # Now we can use the broker’s methods without worrying about which broker it is
    broker.create_order("AAPL", 10, "BUY")
    balance = broker.get_balance()
    print(balance)
    broker.close_position("AAPL", 5)

This setup means we can easily switch brokers by just changing the value of broker_name.


Conclusion

The Strategy Pattern helped us isolate broker-specific logic, making it interchangeable. The Factory Pattern gives us flexibility in selecting which broker to use at runtime. By combining these patterns, our app becomes easy to maintain and extend, allowing us to add new brokers (like Interactive Brokers or others) without changing the core app logic.

These design patterns make the app scalable, flexible, and maintainable—ideal for adding new brokers and growing the trading platform.