Codezerg.AlgoTrader 1.0.1

dotnet add package Codezerg.AlgoTrader --version 1.0.1
                    
NuGet\Install-Package Codezerg.AlgoTrader -Version 1.0.1
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Codezerg.AlgoTrader" Version="1.0.1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Codezerg.AlgoTrader" Version="1.0.1" />
                    
Directory.Packages.props
<PackageReference Include="Codezerg.AlgoTrader" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Codezerg.AlgoTrader --version 1.0.1
                    
#r "nuget: Codezerg.AlgoTrader, 1.0.1"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Codezerg.AlgoTrader@1.0.1
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Codezerg.AlgoTrader&version=1.0.1
                    
Install as a Cake Addin
#tool nuget:?package=Codezerg.AlgoTrader&version=1.0.1
                    
Install as a Cake Tool

Codezerg.AlgoTrader

NuGet NuGet Downloads License: MIT

A C# algorithmic trading library for post-market stock strategy evaluation and backtesting.

Features

  • Strategy Framework: Clean, event-driven architecture for implementing trading strategies
  • Technical Indicators: Built-in SMA, EMA, RSI, MACD, Bollinger Bands, ATR
  • Backtesting Engine: Full-featured backtesting with performance metrics
  • Multiple Data Sources: CSV files and EODHD API support
  • Performance Analytics: Sharpe ratio, max drawdown, win rate, profit factor, and more

Design Constraints

AlgoTrader is intentionally designed with specific constraints to focus on strategy evaluation:

Constraint Description
Cash accounts only No margin trading
Long positions only No short selling
Daily timeframe and above D1, W1, MN1 only
Bar data only No tick data support
Complete fills only No partial order fills
Post-market execution Orders execute at bar close

Installation

NuGet Package

dotnet add package Codezerg.AlgoTrader

Or via the Package Manager:

Install-Package Codezerg.AlgoTrader

Requirements

  • .NET 8.0 or later
  • (Optional) EODHD API key for live data

Build from Source

dotnet build

Run Tests

dotnet test

Quick Start

1. Create a Strategy

using AlgoTrader.Indicators;
using AlgoTrader.Strategy;

public class GoldenCrossStrategy : StrategyBase
{
    private iSMA? _fastMa;
    private iSMA? _slowMa;

    // Anchor symbol - determines when OnEvaluate() fires
    public override string Symbol => "SPY";

    protected override void OnInit()
    {
        // Initialize indicators
        _fastMa = new iSMA(Close, 50);
        _slowMa = new iSMA(Close, 200);
    }

    protected override void OnEvaluate()
    {
        // Update indicators
        _fastMa!.Update();
        _slowMa!.Update();

        if (!_fastMa.Ready || !_slowMa.Ready)
            return;

        // Golden cross: fast MA crosses above slow MA
        var goldenCross = _fastMa[1] <= _slowMa[1] && _fastMa[0] > _slowMa[0];

        // Death cross: fast MA crosses below slow MA
        var deathCross = _fastMa[1] >= _slowMa[1] && _fastMa[0] < _slowMa[0];

        if (goldenCross && !HasPosition(Symbol))
        {
            var shares = SharesForAmount(Symbol, EquityPercent(95m));
            if (shares > 0)
                Buy(Symbol, shares);
        }
        else if (deathCross && HasPosition(Symbol))
        {
            ClosePosition(Symbol);
        }
    }
}

2. Run a Backtest

using AlgoTrader.Broker;
using AlgoTrader.Core;
using AlgoTrader.Data;

// Create data provider (CSV or EODHD)
var dataProvider = new CsvDataProvider("./data");
// Or: var dataProvider = new EodhdDataProvider(apiKey);

// Create broker with initial capital
var broker = new BacktestBroker(100_000m, commissionPerShare: 0.01m);

// Configure engine
var config = new EngineConfig
{
    Timeframe = Timeframe.D1,
    WarmupBars = 200  // Allow indicators to initialize
};

var engine = new Engine(dataProvider, broker, config);
engine.AddStrategy(new GoldenCrossStrategy());

// Run backtest
var result = await engine.RunAsync("2020-01-01", "2024-12-31");

// Print results
Console.WriteLine(result.Summary());

3. View Results

═══════════════════════════════════════════════════════════════
                      BACKTEST RESULTS
═══════════════════════════════════════════════════════════════

Period:           2020-01-01 to 2024-12-31
Initial Equity:   $100,000.00
Final Equity:     $142,350.00

───────────────────────────────────────────────────────────────
                         RETURNS
───────────────────────────────────────────────────────────────
Total Return:     42.35% ($42,350.00)
Annualized:       8.47%

───────────────────────────────────────────────────────────────
                          RISK
───────────────────────────────────────────────────────────────
Sharpe Ratio:     0.85
Max Drawdown:     15.23% ($15,230.00)

───────────────────────────────────────────────────────────────
                         TRADES
───────────────────────────────────────────────────────────────
Total Trades:     12
Win Rate:         58.33% (7W / 5L)
Profit Factor:    2.15

Architecture

Strategy Layer (user strategies)
       ↓
Engine Layer (orchestrates execution)
       ↓
   ┌───┴───┐
   ↓       ↓
Data    Broker

Project Structure

src/AlgoTrader/
├── Core/           # Engine, types, events, configuration
├── Domain/         # Bar, Order, Position, Account
├── Data/           # DataSeries, SymbolData, providers
├── Broker/         # IBroker, BacktestBroker, Trade
├── Strategy/       # StrategyBase, StrategyContext
├── Indicators/     # SMA, EMA, RSI, MACD, Bands, ATR
└── Analysis/       # Metrics, BacktestResult

examples/           # Example strategies
tests/              # Unit tests

Strategy Development

Strategy Lifecycle

public class MyStrategy : StrategyBase
{
    public override string Symbol => "SPY";  // Anchor symbol

    protected override void OnInit()
    {
        // Called once at start - initialize indicators
    }

    protected override void OnEvaluate()
    {
        // Called after each bar - implement trading logic
    }

    protected override void OnDeinit()
    {
        // Called once at end - cleanup
    }
}

Data Access

Data is accessed using reverse indexing where 0 is the most recent bar:

// Anchor symbol data (shorthand)
Close[0]    // Current bar close
Close[1]    // Previous bar close
Open[0]     // Current bar open
High[0]     // Current bar high
Low[0]      // Current bar low
Volume(0)   // Current bar volume

// Multi-symbol data access
Data["AAPL"].Close[0]    // AAPL current close
Data["MSFT"].High[1]     // MSFT previous high

Trading Functions

// Submit orders
Buy(symbol, quantity);                           // Market buy
Buy(symbol, quantity, price, OrderType.Limit);   // Limit buy
Sell(symbol, quantity);                          // Market sell
ClosePosition(symbol);                           // Close entire position

// Position info
HasPosition(symbol)      // Check if has position OR pending buy
PositionSize(symbol)     // Current shares held

// Sizing helpers
EquityPercent(50m)                    // 50% of current equity
SharesForAmount(symbol, amount)       // Shares purchasable for amount

Order Flow

Orders placed in OnEvaluate() are queued and execute after the method returns:

OnEvaluate() called
    ↓
Buy/Sell orders queued
    ↓
OnEvaluate() returns
    ↓
Orders execute at bar close price
    ↓
Next bar begins

Use HasPosition(symbol) to check both existing positions AND pending buy orders, preventing duplicate orders in the same evaluation cycle.

Indicators

All indicators use the i prefix naming convention:

Indicator Class Description
SMA iSMA Simple Moving Average
EMA iEMA Exponential Moving Average
RSI iRSI Relative Strength Index (Wilder's smoothing)
MACD iMACD Moving Average Convergence Divergence
Bollinger Bands iBands Bollinger Bands (SMA +/- std dev)
ATR iATR Average True Range

Usage Example

protected override void OnInit()
{
    // Moving averages
    var sma = new iSMA(Close, 20);
    var ema = new iEMA(Close, 12);

    // RSI
    var rsi = new iRSI(Close, 14);

    // MACD
    var macd = new iMACD(Close, 12, 26, 9);

    // Bollinger Bands
    var bands = new iBands(Close, 20, 2.0m);

    // ATR (requires SymbolData)
    var atr = new iATR(Data["SPY"], 14);
}

protected override void OnEvaluate()
{
    // Update indicators
    sma.Update();
    ema.Update();
    rsi.Update();
    macd.Update();
    bands.Update();
    atr.Update();

    // Access values
    if (sma.Ready)
    {
        var currentSma = sma[0];
        var previousSma = sma[1];
    }

    // MACD lines
    if (macd.Ready)
    {
        var macdLine = macd.Main[0];
        var signalLine = macd.Signal[0];
        var histogram = macd.Histogram[0];
    }

    // Bollinger Bands
    if (bands.Ready)
    {
        var upper = bands.Upper[0];
        var middle = bands.Middle[0];
        var lower = bands.Lower[0];
    }
}

Data Providers

CSV Data Provider

Reads from local CSV files with naming convention {SYMBOL}_{TIMEFRAME}.csv:

data/
├── SPY_D1.csv
├── AAPL_D1.csv
└── MSFT_D1.csv

CSV Format:

date,open,high,low,close,volume
2020-01-02,323.54,324.89,322.53,324.87,32145000
2020-01-03,321.16,323.64,321.05,322.41,36156000

Usage:

var provider = new CsvDataProvider("./data");

EODHD Data Provider

Fetches data from the EODHD API:

// Set environment variable
// Windows: set EODHD_API_KEY=your_api_key
// Linux/Mac: export EODHD_API_KEY=your_api_key

var apiKey = Environment.GetEnvironmentVariable("EODHD_API_KEY");
await using var provider = new EodhdDataProvider(apiKey);

Account State Persistence

Account state (balance, positions, orders, trades) can be saved and loaded for two main use cases:

  1. Backtesting/Development - Resume backtests or analyze results
  2. Daily Execution - Load state, execute latest bar, save state
using Codezerg.AlgoTrader.Domain;

// Load existing account or create new one
Account account;
if (File.Exists("account.json"))
    account = Account.LoadFromFile("account.json");
else
    account = new Account(100_000m);

// Create broker with the account
var broker = new BacktestBroker(account, commissionPerShare: 0.01m);

// ... run strategy ...

// Save account state
account.SaveToFile("account.json");

Saved State Format (JSON):

{
  "Balance": 95234.50,
  "Positions": [
    {
      "Symbol": "SPY",
      "Quantity": 100,
      "AvgPrice": 450.25,
      "OpenedAt": "2024-01-15T00:00:00Z",
      "MarketPrice": 455.80
    }
  ],
  "Orders": [],
  "Trades": [
    {
      "OrderId": "abc-123",
      "Symbol": "SPY",
      "Side": "Buy",
      "Quantity": 100,
      "Price": 450.25,
      "Timestamp": "2024-01-15T00:00:00Z",
      "Commission": 1.00,
      "Pnl": 0
    }
  ]
}

Example Strategies

The examples/ directory contains ready-to-use strategies:

Strategy Description
BuyAndHoldStrategy Simple benchmark - buy once and hold
GoldenCrossStrategy 50/200 SMA crossover
MeanReversionStrategy RSI oversold/overbought with trend filter
MomentumStrategy Multi-symbol momentum rotation

Running Examples

# Set API key (required for EODHD data)
export EODHD_API_KEY=your_api_key

# Run default example
dotnet run --project examples/Codezerg.AlgoTrader.Examples.csproj

# Run stateful example (demonstrates account persistence)
dotnet run --project examples/Codezerg.AlgoTrader.Examples.csproj -- --stateful

Performance Metrics

The backtest result includes comprehensive metrics:

Metric Description
Total Return Percentage and dollar return
Annualized Return Compound annual growth rate
Sharpe Ratio Risk-adjusted return (assumes 2% risk-free rate)
Max Drawdown Largest peak-to-trough decline
Total Trades Number of completed round trips
Win Rate Percentage of profitable trades
Profit Factor Gross profit / gross loss
Average Win/Loss Mean winning/losing trade
Largest Win/Loss Best/worst single trade
Total Commission Sum of all commissions paid

Type Conventions

  • Prices: Use decimal (not float/double) for all monetary values
  • Timestamps: Use DateTime for all time-related values
  • Bar: Immutable record type
  • Order/Position: Mutable classes with state management
  • Broker: Async interface (HTTP-ready design)

Configuration

var config = new EngineConfig
{
    Timeframe = Timeframe.D1,    // D1, W1, or MN1
    WarmupBars = 200             // Bars before trading starts
};

License

MIT License - see LICENSE file for details.

Contributing

  1. Fork the repository
  2. Create a feature branch
  3. Make your changes
  4. Run tests: dotnet test
  5. Submit a pull request
Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.1 144 12/12/2025
1.0.0 121 12/12/2025