Skip to main content

Fractal is the ultimate DeFi research library for strategies development and backtesting created by Logarithm Labs.

Project description

Fractal

PyPI version Python Versions License: MIT

Fractal is the ultimate DeFi research library for strategies development and backtesting created by Logarithm Labs.

Overview

Fractal offers a modular architecture where each component plays a crucial role in constructing and managing complex DeFi strategies. Whether you’re experimenting with automated market-making, liquidity management, or yield strategies, Fractal provides the building blocks and pipelines necessary for thorough analysis and execution.

  • Entities represent a scope of DeFi primitives with behavior replicated in Python. Each entity holds global market states (e.g., prices, yield rates) along with its own internal states (e.g., balances, open positions, LP positions).
  • Strategies contain management logic on top of the entites with actions execution.
  • Loaders simplify the process of gathering and preparing market data from various DeFi protocols. Fractal provides a collection of ad-hoc ETL tools to quickly load data, making it easier to construct observations for dynamic strategy execution.
  • Fractal’s engine includes robust backtesting and simulation pipelines for strategy optimization powered by MLFlow:

Quick Start

Install:

pip install fractal-defi

Start with a built-in strategies: Run MLFlow server:

mlflow server --host 127.0.0.1 --port 8080

Set up your experiment:

import numpy as np
import pandas as pd

from typing import List
from datetime import datetime, UTC
from sklearn.model_selection import ParameterGrid

from fractal.loaders import PriceHistory, RateHistory
from fractal.loaders import HyperliquidFundingRatesLoader, HyperLiquidPerpsPricesLoader

from fractal.core.base import Observation
from fractal.core.pipeline import (
    DefaultPipeline, MLFlowConfig, ExperimentConfig)
from fractal.core.entities import UniswapV3LPGlobalState, HyperLiquidGlobalState

from fractal.strategies.hyperliquid_basis import HyperliquidBasis


def get_observations(
        rate_data: RateHistory, price_data: PriceHistory,
        start_time: datetime = None, end_time: datetime = None
    ) -> List[Observation]:
    """
    Get observations from the pool and price data for the ManagedBasisStrategy.

    Returns:
        List[Observation]: The observation list for ManagedBasisStrategy.
    """
    observations_df: pd.DataFrame = price_data.join(rate_data)
    observations_df['rate'] = observations_df['rate'].fillna(0)
    observations_df = observations_df.loc[start_time:end_time]
    observations_df = observations_df.dropna()
    start_time = observations_df.index.min()
    if end_time is None:
        end_time = observations_df.index.max()
    observations_df = observations_df.sort_index()
    return [
        Observation(
            timestamp=timestamp,
            states={
                'SPOT': UniswapV3LPGlobalState(price=price, tvl=0, volume=0, fees=0, liquidity=0),  # we need only spot price
                'HEDGE': HyperLiquidGlobalState(mark_price=price, funding_rate=rate)
            }
        ) for timestamp, (price, rate) in observations_df.iterrows()
    ]


def build_observations(
        ticker: str, start_time: datetime = None, end_time: datetime = None,
    ) -> List[Observation]:
    """
    Build observations for the ManagedBasisStrategy from the given start and end time.
    """
    rate_data: RateHistory = HyperliquidFundingRatesLoader(
          ticker, start_time=start_time, end_time=end_time).read(with_run=True)
    prices: PriceHistory = HyperLiquidPerpsPricesLoader(
          ticker, interval='1h', start_time=start_time, end_time=end_time).read(with_run=True)
    return get_observations(rate_data, prices, start_time, end_time)


def build_grid():
    raw_grid = ParameterGrid({
        'MIN_LEVERAGE': np.arange(1, 12, 1).tolist(),
        'TARGET_LEVERAGE': np.arange(1, 12, 1).tolist(),
        'MAX_LEVERAGE': np.arange(1, 12, 1).tolist(),
        'INITIAL_BALANCE': [1_000_000]
    })

    valid_grid = [
        params for params in raw_grid
        if round(params['MIN_LEVERAGE'], 1) < round(params['TARGET_LEVERAGE'], 1) < round(params['MAX_LEVERAGE'], 1)
    ]
    return valid_grid


if __name__ == '__main__':
    # Strategy environment
    ticker: str = 'BTC'
    start_time = datetime(2025, 1, 1, tzinfo=UTC)
    end_time = datetime(2025, 3, 1, tzinfo=UTC)
    experiment_name = f'hl_basis_{ticker}_{start_time.strftime("%Y-%m-%d")}_{end_time.strftime("%Y-%m-%d")}'
    HyperliquidBasis.MAX_LEVERAGE = 45
    
    # Mlflow setup
    mlflow_config: MLFlowConfig = MLFlowConfig(
        mlflow_uri='http://127.0.01:8080',
        experiment_name=experiment_name,
    )

    # Load data and build observations
    observations = build_observations(ticker, start_time, end_time)
    assert len(observations) > 0

    # Experiment setup
    experiment_config: ExperimentConfig = ExperimentConfig(
        strategy_type=HyperliquidBasis,
        backtest_observations=observations,
        window_size=24,  # number of scenarios from history
        params_grid=build_grid(),
        debug=True,
    )

    # Run the DefualtPipeline
    pipeline: DefaultPipeline = DefaultPipeline(
        experiment_config=experiment_config,
        mlflow_config=mlflow_config
    )
    pipeline.run()

Run your pipeline:

╰─➤  python3 fractal_basis.py
🏃 View run whimsical-sheep-752 at: http://127.0.01:8080/#/experiments/743858278487100844/runs/eeb3db5833b54f38aa9eb4b31990f6e2
🧪 View experiment at: http://127.0.01:8080/#/experiments/743858278487100844
🏃 View run useful-crab-883 at: http://127.0.01:8080/#/experiments/743858278487100844/runs/d728d6f94b1d4f708e96e628111f215e
🧪 View experiment at: http://127.0.01:8080/#/experiments/743858278487100844
🏃 View run bittersweet-goat-277 at: http://127.0.01:8080/#/experiments/743858278487100844/runs/31fc73bfef6d47e296dea8880f161821
🧪 View experiment at: http://127.0.01:8080/#/experiments/743858278487100844
🏃 View run gifted-gnu-901 at: http://127.0.01:8080/#/experiments/743858278487100844/runs/c88004f211c74be8964e992a168addf6
🧪 View experiment at: http://127.0.01:8080/#/experiments/743858278487100844

Examples

Explore our example strategies to jumpstart your DeFi research:

  • HODL Strategy: Start with a straightforward HODL.
    View Example

  • Tau Reset Strategy: Focused on active liquidity management within Uniswap V3.
    View Example

  • Managed Basis Strategy: Strategies addressing basis management.
    View Example

  • Agent Trading Backtesting: A comprehensive guide for backtesting AI agent trading strategies.
    View Example

Documentation

For detailed technical documentation and comprehensive code references, please explore the following resources:

  • Fractal Tech Docs:
    Dive into in-depth guides, technical details, and conceptual overviews at our Tech Docs site.

  • Code References:
    Access comprehensive API documentation and code references at our Code References page.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

fractal_defi-1.2.1.tar.gz (44.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

fractal_defi-1.2.1-py3-none-any.whl (65.6 kB view details)

Uploaded Python 3

File details

Details for the file fractal_defi-1.2.1.tar.gz.

File metadata

  • Download URL: fractal_defi-1.2.1.tar.gz
  • Upload date:
  • Size: 44.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.12.8

File hashes

Hashes for fractal_defi-1.2.1.tar.gz
Algorithm Hash digest
SHA256 78cf0990d5f28940a639191cdc6f27bd12baa8acd4d1e8f46b88a884cc99c312
MD5 b6f9f4c362d9571f2ebc15810cba259d
BLAKE2b-256 1c0eb9b829ec8ea4ab5d3effcd202bac286b8e3dd12f9c24b27e1fe88cbd3424

See more details on using hashes here.

File details

Details for the file fractal_defi-1.2.1-py3-none-any.whl.

File metadata

  • Download URL: fractal_defi-1.2.1-py3-none-any.whl
  • Upload date:
  • Size: 65.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.12.8

File hashes

Hashes for fractal_defi-1.2.1-py3-none-any.whl
Algorithm Hash digest
SHA256 ef86cda34eb0bf9b2d38425802418238c1063459913687c08efd6228a9eec271
MD5 2a58ae8eba5371bdfe92416315db9957
BLAKE2b-256 f78d878f90bc8cdabf18640d67f109f3f369d06b63741ef3d455607827257250

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page