WalkForward.Net
0.3.0-beta.1
dotnet add package WalkForward.Net --version 0.3.0-beta.1
NuGet\Install-Package WalkForward.Net -Version 0.3.0-beta.1
<PackageReference Include="WalkForward.Net" Version="0.3.0-beta.1" />
<PackageVersion Include="WalkForward.Net" Version="0.3.0-beta.1" />
<PackageReference Include="WalkForward.Net" />
paket add WalkForward.Net --version 0.3.0-beta.1
#r "nuget: WalkForward.Net, 0.3.0-beta.1"
#:package WalkForward.Net@0.3.0-beta.1
#addin nuget:?package=WalkForward.Net&version=0.3.0-beta.1&prerelease
#tool nuget:?package=WalkForward.Net&version=0.3.0-beta.1&prerelease
WalkForward.Net
Time-series cross-validation without lookahead bias for .NET.
The Problem
Random k-fold cross-validation is broken for time series. It shuffles data, so your "test" fold may contain Tuesday's data while "training" on Wednesday's. The model learns the future to predict the past -- results look great, production performance is terrible. This is called lookahead bias.
WalkForward.Net generates temporally-correct train/test splits that respect the arrow of time, with configurable embargo gaps to prevent subtle information leakage.
Installation
dotnet add package WalkForward.Net
Targets .NET 8.0 and .NET 9.0. Zero runtime dependencies.
Quick Start
Backward-Looking Mode
using WalkForward;
// Generate folds from 10,000 data points at 15-minute frequency
var folds = new FoldBuilder()
.WithDataPoints(10000)
.WithDataFrequency(TimeSpan.FromMinutes(15))
.BackwardLooking()
.WithTrainingWindow(TimeSpan.FromDays(90))
.WithTestWindow(TimeSpan.FromDays(7))
.WithEmbargo(TimeSpan.FromHours(4))
.Build();
// Use folds with your own model/strategy
var returns = new double[folds.Count];
for (var i = 0; i < folds.Count; i++)
{
var trainData = allData[folds[i].TrainRange];
var testData = allData[folds[i].TestRange];
returns[i] = MyModel.Train(trainData).Evaluate(testData);
}
// Compute aggregate consistency metrics
var metrics = Consistency.Compute(returns);
// metrics.ConsistencyPercent -> 60.0 (3 of 5 folds profitable)
// metrics.MagnitudeConsistency -> 0.72 (Sortino-like, [0,1])
// metrics.WorstFold -> -0.02
// metrics.AverageReturn -> 0.022
Forward-Looking Mode
var folds = new FoldBuilder()
.WithDataPoints(50000)
.WithDataFrequency(TimeSpan.FromMinutes(15))
.ForwardLooking()
.WithTrainingWindow(TimeSpan.FromDays(30))
.WithTestWindow(TimeSpan.FromDays(7))
.WithStride(TimeSpan.FromDays(3))
.WithEmbargo(TimeSpan.FromHours(4))
.Build();
API Reference
| Type | Description |
|---|---|
FoldBuilder |
Entry point. Configure data points and frequency, then select a mode. |
BackwardLookingBuilder |
Backward-looking mode configuration: training/test windows, embargo, warmup, max folds. |
ForwardLookingBuilder |
Forward-looking mode configuration: adds stride to backward-looking options. |
Fold |
Single fold with int boundaries and Range properties for array slicing. |
BackwardLookingOptions |
Backward-looking configuration record (used internally by BackwardLookingBuilder). |
ForwardLookingOptions |
Forward-looking configuration record (used internally by ForwardLookingBuilder). |
FoldMode |
Enum: BackwardLooking, ForwardLooking. |
Consistency |
Static methods: Compute() for returns, ForClassifier() for ML accuracy. |
ConsistencyMetrics |
Returns-based metrics: consistency %, magnitude consistency, worst fold, average return. |
ClassifierConsistencyMetrics |
Classifier metrics: average accuracy, log-loss, consistency above baseline. |
Modes
Backward-Looking
Starts from the most recent data and works backwards. Each fold uses the same fixed-size training window, placed just before its test window. Fold 1 tests the newest data, fold 2 tests the next-oldest chunk, and so on.
Use this when recent data matters most and you want to evaluate how a model trained on a fixed history performs across successive past periods.
Time ──────────────────────────────────────────────────────────►
Data: [==================================================]
newest
▼
Fold 1: [===TRAIN===]~embargo~[==TEST==] │
Fold 2: [===TRAIN===]~embargo~[==TEST==] │
Fold 3: [===TRAIN===]~embargo~[==TEST==] │
▲
oldest
All training windows are the same size. Folds are built right-to-left from the end of the dataset.
Forward-Looking
Starts from the oldest data and slides forward. Each fold advances by a configurable stride. Both training and test windows stay the same size throughout.
Use this when you want to simulate deploying a model repeatedly over time -- train on a fixed lookback, test on the next period, advance, repeat.
Time ──────────────────────────────────────────────────────────►
Data: [==================================================]
oldest
▼
Fold 1: [===TRAIN===]~embargo~[==TEST==]
Fold 2: [===TRAIN===]~embargo~[==TEST==]
Fold 3: [===TRAIN===]~embargo~[==TEST==]
▲
newest
|------|
stride (how far each fold shifts forward)
The stride defaults to the test window size (no overlap between test windows), but you can set it smaller for overlapping tests or larger for gaps.
Embargo
The embargo gap between training and test windows prevents information leakage from autocorrelated features. If your model predicts 4 hours ahead, the last training sample's label was computed using data that overlaps with the test window. The embargo excludes this zone.
Without embargo: [====TRAIN====][==TEST==]
^-- label leakage
With embargo: [====TRAIN====][///GAP///][==TEST==]
^-- excluded zone
Embargo is specified as a TimeSpan and automatically converted to the correct number of data points based on your data frequency.
Classifier Consistency
For ML classification models, use Consistency.ForClassifier() with per-fold accuracy and log-loss arrays:
var metrics = Consistency.ForClassifier(
foldAccuracies: new[] { 0.61, 0.58, 0.63, 0.60, 0.55 },
foldLogLosses: new[] { 0.65, 0.68, 0.62, 0.64, 0.70 },
baselineAccuracy: 0.50);
// metrics.AverageAccuracy -> 0.594
// metrics.AverageLogLoss -> 0.658
// metrics.ConsistencyAboveBaseline -> 100.0 (all folds above 0.50)
// metrics.FoldCount -> 5
Requirements
- .NET 8.0+ or .NET 9.0+
- Zero runtime dependencies
- AOT and trimming compatible
License
Apache 2.0
| Product | Versions 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 is compatible. 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. |
-
net8.0
- No dependencies.
-
net9.0
- No dependencies.
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 |
|---|---|---|
| 0.3.0-beta.1 | 92 | 3/30/2026 |
| 0.2.0-beta.1 | 64 | 3/29/2026 |
| 0.1.0-beta.1 | 121 | 3/28/2026 |