EA Backtest Data Normalizer
Pricing
from $5,000.00 / 1,000 symbol×timeframe job completeds
EA Backtest Data Normalizer
Pulls historical forex price data from Dukascopy's public archive and normalizes it into clean, consistent OHLCV format ready for Expert Advisor backtesting. Flat $5/job pricing, $6 if data gaps are detected.
Pricing
from $5,000.00 / 1,000 symbol×timeframe job completeds
Rating
0.0
(0)
Developer
joseph fadero
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
8 days ago
Last modified
Categories
Share
Pulls historical forex price data from Dukascopy's public archive and normalizes it into clean, consistent OHLCV format ready for Expert Advisor backtesting.
What it does
- Fetches historical candles for a forex symbol/timeframe/date-range from Dukascopy's public tick archive (no API key needed — this is free, public market data).
- Normalizes the raw data into a consistent per-candle shape:
{symbol, timeframe, timestamp (ISO 8601 UTC), open, high, low, close, volume}. - Sorts chronologically and removes exact-timestamp duplicates.
- Walks the sequence and detects gaps — timestamp jumps wider than the timeframe's expected interval — while correctly ignoring expected weekend market closures (Friday ~21:00 UTC through Sunday ~21:00 UTC). It never interpolates or fills missing candles, it only flags them, so you always know exactly what's real market data vs. a hole in the feed.
- Pushes one
dataQualityReportsummary record per job with everything you need to sanity-check the dataset before feeding it to a backtest.
Data source: Dukascopy (via dukascopy-node)
This Actor uses the community npm package dukascopy-node to pull data from Dukascopy's public bi5-compressed historical tick archive. It worked cleanly out of the box — no need to hand-roll the binary archive format. Verified live while building this Actor:
- Real OHLCV data comes back correctly for any historical range.
- Dukascopy's public archive has a publication lag of roughly 1-2 weeks. Requesting a date range that is too recent (e.g. the last few days) will return zero rows, not an error. If your job returns an empty dataset, widen the range further into the past.
- Instrument codes are lowercase internally (
eurusd) — this Actor accepts the symbol however you type it (e.g.EURUSD) and lowercases it automatically before calling Dukascopy.
Input
| Field | Type | Default | Notes |
|---|---|---|---|
symbol | string | EURUSD | Any Dukascopy-supported forex instrument code, e.g. EURUSD, GBPUSD, USDJPY. |
timeframe | select | H1 | One of M1, M5, M15, H1, H4, D1. |
dateFrom | date | 2026-08-25 | Start of the range (UTC), YYYY-MM-DD. |
dateTo | date | 2026-08-26 | End of the range (UTC), YYYY-MM-DD. |
source | select | dukascopy | Only dukascopy is currently supported. |
Important — the default date range is intentionally narrow (1 day). It exists so the Actor runs in a few seconds for automated testing/QA. For real backtesting, widen dateFrom/dateTo to whatever range your EA needs — months or years of data work fine, just expect the run to take longer and produce a much larger dataset (a full year of M1 data is roughly 370K candles). Also remember the 1-2 week publication lag noted above: don't set dateTo too close to today.
Output
Per candle (one dataset record each):
{"symbol": "EURUSD","timeframe": "H1","timestamp": "2026-08-25T00:00:00.000Z","open": 1.16679,"high": 1.16708,"low": 1.16671,"close": 1.16686,"volume": 4889.53}
One summary record per job, at the end of the dataset:
{"type": "dataQualityReport","symbol": "EURUSD","timeframe": "H1","dateFrom": "2026-08-25","dateTo": "2026-08-26","source": "dukascopy","candleCount": 24,"gapsDetected": [{ "from": "2026-08-25T09:00:00.000Z", "to": "2026-08-25T12:00:00.000Z", "reason": "2 missing H1 candles (non-weekend gap, likely holiday or feed outage)" }],"duplicatesRemoved": 0,"sourceCoverage": {"requestedFrom": "2026-08-25","requestedTo": "2026-08-26","actualFirstCandle": "2026-08-25T00:00:00.000Z","actualLastCandle": "2026-08-25T23:00:00.000Z"},"generatedAt": "2026-09-15T17:29:57.944Z"}
Filter the dataset on type === "dataQualityReport" to separate the summary from the candle rows, or just take the last record.
Pricing (Pay Per Event)
Flat per-job pricing — you're charged once per completed job, not per candle, no matter how large the date range:
| Event | Price | When |
|---|---|---|
| Actor Start | $0.05 | Built-in, charged once per run at startup. |
| Symbol×Timeframe Job Completed | $5.00 | Job completed successfully with no data-quality gaps detected. |
| Symbol×Timeframe Job Completed With Gap Report | $6.00 | Job completed successfully and gaps were detected and flagged in the report. |
Exactly one of the two "Job Completed" events is charged per run — never both, and never per candle row.
Notes on gap detection
Forex markets close every week from roughly Friday 21:00 UTC to Sunday 21:00 UTC. That closure is expected and is never flagged as a gap. Anything else — a missed weekday candle, an exchange holiday, a feed outage — is flagged with the number of missing candles and a from/to timestamp range, so you can decide for yourself whether it matters for your strategy. The normalizer never fabricates or interpolates data to fill a gap.