Flumine Betting Trading Framework

repository·master·Indexed 42 days ago

https://github.com/betcode-org/flumine

An open-source, event-based trading framework for sports betting designed to simplify the development and execution of betting strategies. It provides efficient data stream handling, risk management, and multi-venue support, requiring Python 3.10 or higher. The framework utilizes a FIFO event-driven architecture to handle market data updates, order changes, and system signals, with built-in support for simulation via time monkeypatching for backtesting.

Tokens
22.8K
Snippets
73
Records
96
Agent score
49%

What's inside Flumine

  1. Understand Trading Controls and Order Violations

    master

    Flumine performs validation checks before placing any order. If an order fails to meet the criteria defined by Client or Trading controls, the order is not executed, and its status is updated to Violation.

    Client Controls

    • MaxTransactionCount: Ensures the transaction count does not exceed the Betfair limit (5000 per hour).

    Trading Controls

    • OrderValidation: Validates that the order size and odds are acceptable.
    • StrategyExposure: Ensures the order does not violate constraints defined in your strategy, specifically:
      • strategy.validate_order
      • strategy.max_order_exposure
      • strategy.max_selection_exposure
  2. Understand the flumine event-driven architecture

    master
    flumine uses an event-driven design where a main thread processes events sequentially using a FIFO (First-In-First-Out) queue. The main loop runs in __main__ and handles all incoming events one by one. This architecture allows the framework to react to market updates, order changes, and system signals in a predictable order.
  3. Configure Stream-to-Strategy Relationships in v3

    master

    Flumine v3 allows for complex mapping between market data streams and trading strategies. You can implement the following patterns:

    One Stream to Multiple Strategies

    Create a single stream object and pass it to multiple strategy instances. This is efficient when multiple strategies need to react to the same market data.

    Multiple Streams to One Strategy

    Pass a list of streams to a single strategy using the streams parameter. This allows a strategy to aggregate data from different market types or filters.

    Dynamic Subscription

    You can subscribe or unsubscribe a strategy from a stream after the strategy has already been initialized using subscribe_to_stream(stream) and unsubscribe_from_stream(stream).

    # One stream to multiple strategies
    stream = BetfairMarketStream(market_filter=...) 
    
    strategy_one = ExampleStrategy(name="one", stream=stream)
    framework.add_strategy(strategy_one)
    
    strategy_two = ExampleStrategy(name="two", stream=stream)
    framework.add_strategy(strategy_two)
    
    # Multiple streams to one strategy
    stream_one = BetfairMarketStream(market_filter=...) 
    stream_two = BetfairMarketStream(market_filter=...) 
    
    strategy = ExampleStrategy(name="one", streams=[stream_one, stream_two])
    framework.add_strategy(strategy)
    
    # Dynamic subscription
    strategy.subscribe_to_stream(stream)
    strategy.unsubscribe_from_stream(stream)
  4. Use different Stream types (Data and Order streams)

    master

    Depending on your goal, you can use different stream classes:

    1. BetfairDataStream: Used for collecting raw data. Note that process_raw_data is called instead of process_market_book.
    2. BetfairOrderDataStream: Used to record order data as per market.
    3. BetfairMarketStream: The default, providing MarketBook objects.
    from flumine.streams.betfairdatastream import BetfairDataStream
    from flumine.streams.betfairdatastream import BetfairOrderDataStream
    
    # For raw data collection
    strategy = ExampleDataStrategy(
        stream=BetfairDataStream(
            market_filter=streaming_market_filter(event_type_ids=["7"]),
        )
    )
    
    # For recording order data
    strategy = ExampleDataStrategy(
        stream=BetfairOrderDataStream(framework)
    )
  5. Implement a custom strategy with BaseStrategy

    master

    To create a trading strategy, inherit from BaseStrategy. You must implement the following lifecycle methods:

    • check_market_book(self, market, market_book) -> bool: This method is called for every market update. If it returns True, the framework will proceed to call process_market_book. Use this to filter which markets or updates your strategy actually reacts to.
    • process_market_book(self, market, market_book): This is where your core trading logic resides. It is only executed if check_market_book returns True.
    • start(self, flumine) (Optional): Called when the strategy starts.
    • process_orders(self, market, orders) (Optional): Called to handle order updates and lifecycle management (e.g., cancelling, updating, or replacing orders).
    from flumine import BaseStrategy
    
    class ExampleStrategy(BaseStrategy):
        def check_market_book(self, market, market_book) -> bool:
            # Return True to trigger process_market_book
            return True
    
        def process_market_book(self, market, market_book):
            # Your strategy logic here
            pass
  6. Identify supported event types in flumine

    master

    The flumine class handles several types of events. These include market data updates, raw streaming data, and system lifecycle events:

    Market & Data Events:

    • MARKET_CATALOGUE: Contains a Betfair MarketCatalogue object.
    • MARKET_BOOK: Contains a Betfair MarketBook object.
    • RAW_DATA: Contains raw streaming data.
    • CURRENT_ORDERS: Contains a Betfair CurrentOrders object.
    • CLEARED_MARKETS: Contains a Betfair ClearedMarkets object.
    • CLEARED_ORDERS: Contains a Betfair ClearedOrders object.

    System & Lifecycle Events:

    • CLOSE_MARKET: A flumine Close Market update.
    • STRATEGY_RESET: A flumine Strategy Reset update.
    • CUSTOM_EVENT: A flumine Custom event update.
    • TERMINATOR: A flumine End instance update.
  7. What are Background Workers in flumine?

    master

    Background workers run in their own dedicated thread, enabling the execution of cleanup tasks or cron-like functions without blocking the main trading loop. By default, flumine includes several built-in workers to maintain the session and monitor account state:

    • keep_alive: Runs every 1200s (or session_timeout/2) to ensure clients remain logged in.
    • poll_account_balance: Runs every 120s to poll the account balance endpoint.
    • poll_market_catalogue: Runs every 60s to poll the listMarketCatalogue endpoint.
    • poll_market_closure: Checks for closed markets to retrieve cleared orders at both the order and market levels.
  8. Implement a custom strategy using BaseStrategy

    master

    All custom strategies in Flumine must inherit from the BaseStrategy class. This class provides the necessary infrastructure for order/trade execution and lifecycle management. You can define your trading logic by overriding specific lifecycle and market-processing methods.

    from flumine.strategies import BaseStrategy
    
    class MyStrategy(BaseStrategy):
        def __init__(self, **kwargs):
            super().__init__(**kwargs)
    
        def process_market_book(self, market_book):
            # Your trading logic here
            pass
  9. Simulate trading with time monkeypatching

    master
    Simulation in flumine is achieved by monkeypatching the datetime.utcnow() function. This allows strategies to be executed as if they were running in real-time. When using simulation, time-sensitive functions such as market.seconds_to_start and fillKill.seconds behave exactly as they would during a live execution, enabling backtesting or historical data replay with realistic timing.
  10. How to implement a BaseStrategy

    master

    To create a trading strategy, inherit from BaseStrategy and implement the following lifecycle methods:

    • start(self, flumine): Called when the strategy starts.
    • check_market_book(self, market, market_book) -> bool: A filter method. process_market_book will only be executed if this method returns True.
    • process_market_book(self, market, market_book): The main logic loop where you inspect market data and decide to place trades.
    • process_orders(self, market, orders): Logic for handling order updates, such as cancellations, replacements, or updates to persistence.
    from flumine import BaseStrategy
    from flumine.markets.market import Market
    from betfairlightweight.resources import MarketBook
    
    class ExampleStrategy(BaseStrategy):
        def start(self, flumine) -> None:
            print("starting strategy")
    
        def check_market_book(self, market: Market, market_book: MarketBook) -> bool:
            # Only process if market is not CLOSED
            return market_book.status != "CLOSED"
    
        def process_market_book(self, market: Market, market_book: MarketBook) -> None:
            # Your trading logic here
            pass
    
        def process_orders(self, market: Market, orders: list) -> None:
            # Your order management logic here
            pass
  11. How strategies and streams work together

    master

    Strategies in flumine are class-based. A strategy subscribes to a stream to receive data. In the standard configuration, a single strategy subscribes to a single market stream.

    Available stream types include:

    • Single stream (market)
    • Single stream with 'data' (flumine listener)
    • Order stream
    • Custom streams (planned)