Dukascopy DataFeed Guide
The Dukascopy library provides access to free historical market data from Dukascopy Bank SA, covering 1600+ financial instruments.
What is Dukascopy?
Dukascopy Bank SA is a Swiss bank that provides free historical market data (ticks and bars) through their public servers. The TheoryCraft Dukascopy library makes it easy to download and stream this data directly into your backtesting pipelines.
This makes Dukascopy an ideal data source for backtesting forex, equities, commodities, and cryptocurrency strategies.
Available Instruments
| Category | Examples | Count |
|---|---|---|
| Forex Majors | EUR/USD, GBP/USD, USD/JPY | 7 |
| Forex Crosses | EUR/GBP, GBP/JPY, AUD/NZD | 290+ |
| Metals | XAU/USD (Gold), XAG/USD (Silver) | 50+ |
| Stocks | AAPL.US/USD, MSFT.US/USD, GOOGL.US/USD | 1000+ |
| Commodities | Oil, Natural Gas | 10+ |
| Agriculturals | Wheat, Corn, Soybeans | 6 |
Installation
As a Library
Add to your mix.exs:
def deps do
[
{:dukascopy, github: "theorycraft-trading/dukascopy"}
]
endAs a CLI Tool
Install the command-line interface:
mix escript.install github theorycraft-trading/dukascopyCLI Usage
The CLI provides two commands: download and search.
Search for Instruments
Find available instruments by symbol:
# Search for EUR pairs
dukascopy search EUR
# Search for Apple stock
dukascopy search AAPL
# Search for Bitcoin
dukascopy search BTCDownload Data
Download historical data in various formats:
# Daily EUR/USD data for 2024
dukascopy download -i EUR/USD --from 2024-01-01 --to 2024-12-31
# 5-minute bars in JSON format
dukascopy download -i EUR/USD -t m5 --from 2024-01-01 -f json
# Tick data (very granular)
dukascopy download -i EUR/USD -t tick --from 2024-01-01 --to 2024-01-02
# Hourly Gold data with ask prices
dukascopy download -i XAU/USD -t h1 --from 2024-01-01 -p askCLI Options
| Flag | Default | Description |
|---|---|---|
-i, --instrument | - | Instrument symbol (required) |
--from | - | Start date YYYY-MM-DD (required) |
--to | now | End date (YYYY-MM-DD or "now") |
-t, --timeframe | D | tick, m1, m5, m15, m30, h1, h4, D, W, M |
-p, --price-type | bid | bid, ask, mid |
-v, --volume-units | millions | millions, thousands, units |
--flats | false | Include zero-volume bars |
-f, --format | csv | csv, json, ndjson |
-o, --output | ./download | Output directory |
--filename | - | Custom filename (without extension) |
-s, --silent | false | No header output |
--timezone | Etc/UTC | Timezone (e.g., America/New_York) |
--utc-offset | 0 | UTC offset in minutes |
--market-open | 00:00:00 | Market open time (HH:MM:SS) |
--weekly-open | monday | Week start day |
--batch-size | 10 | Parallel downloads per batch |
--batch-pause | 1000 | Pause between batches (ms) |
--cache | false | Enable file caching |
--cache-path | .dukascopy-cache | Cache folder path |
--retries | 3 | Retries per request |
--retry-pause | 500 | Pause between retries (ms) |
-h, --help | - | Display help |
Elixir API
Instruments Module
alias Dukascopy.Instruments
Instruments.all()
["EUR/USD", "GBP/USD", "AAPL.US/USD", ...]
Instruments.forex() # All forex
Instruments.forex_majors() # EUR/USD, GBP/USD, USD/JPY, etc.
Instruments.forex_crosses() # EUR/GBP, GBP/JPY, etc.
Instruments.metals() # XAU/USD, XAG/USD, etc.
Instruments.stocks() # AAPL.US/USD, MSFT.US/USD, etc.
Instruments.commodities() # Oil, Natural Gas, etc.
Instruments.agriculturals() # Wheat, Corn, etc.
Instruments.search("XAU")
["XAU/USD"]
Instruments.search("AAPL")
["AAPL.US/USD"]Streaming Data
The Dukascopy.stream/3 function creates a lazy stream of market data.
stream = Dukascopy.stream("EUR/USD", :ticks, from: ~D[2024-01-01], to: ~D[2024-01-02])
for tick <- stream do
IO.puts("#{tick.time}: bid=#{tick.bid} ask=#{tick.ask}")
end
2024-01-01 00:00:00.123Z: bid=1.10452 ask=1.10455
2024-01-01 00:00:00.456Z: bid=1.10453 ask=1.10456
2024-01-01 00:00:00.789Z: bid=1.10451 ask=1.10454
...
stream = Dukascopy.stream("EUR/USD", :m5, from: ~D[2024-01-01], to: ~D[2024-01-31])
for bar <- stream do
IO.puts("#{bar.time}: O=#{bar.open} H=#{bar.high} L=#{bar.low} C=#{bar.close}")
end
2024-01-01 00:00:00Z: O=1.10450 H=1.10480 L=1.10445 C=1.10472
2024-01-01 00:05:00Z: O=1.10472 H=1.10495 L=1.10468 C=1.10491
2024-01-01 00:10:00Z: O=1.10491 H=1.10502 L=1.10485 C=1.10498
...Stream Options
Date Range (required):
Provide either :from and :to (half-open interval [from, to)) or :date_range (inclusive Date.Range).
# Using from/to
Dukascopy.stream("EUR/USD", :h1, from: ~D[2024-01-01], to: ~D[2024-02-01])
# Using date_range
Dukascopy.stream("EUR/USD", :h1, date_range: Date.range(~D[2024-01-01], ~D[2024-01-31]))All Options:
| Option | Default | Description |
|---|---|---|
:price_type | :bid | :bid, :ask, or :mid |
:timezone | "Etc/UTC" | Timezone string (supports DST) |
:volume_units | :millions | :millions, :thousands, or :units |
:ignore_flats | true | Skip zero-volume bars |
:batch_size | 10 | Parallel requests per batch |
:pause_between_batches_ms | 1000 | Delay between batches (ms) |
:use_cache | false | Enable file caching |
:cache_folder_path | ".dukascopy-cache" | Cache directory |
:max_retries | 3 | Retry attempts per request |
:market_open | ~T[00:00:00] | Market open time for alignment |
:weekly_open | :monday | Week start day |
Price Types
Dukascopy.stream("EUR/USD", :h1, price_type: :bid, from: ~D[2024-01-01]) # Bid (default)
Dukascopy.stream("EUR/USD", :h1, price_type: :ask, from: ~D[2024-01-01]) # Ask
Dukascopy.stream("EUR/USD", :h1, price_type: :mid, from: ~D[2024-01-01]) # MidIntegration with TheoryCraft
Use Dukascopy.DataFeed as a data source in your MarketSource pipeline:
alias TheoryCraft.MarketSource
opts = [
instrument: "EUR/USD",
granularity: :ticks,
from: ~D[2024-01-01],
to: ~D[2024-01-31]
]
market =
%MarketSource{}
|> MarketSource.add_data({Dukascopy.DataFeed, opts}, name: "EURUSD")
|> MarketSource.resample("m5", name: "EURUSD_m5")
|> MarketSource.resample("h1", name: "EURUSD_h1")
for event <- MarketSource.stream(market) do
IO.inspect(event)
endTimeframe Reference
Timeframes can be atoms or strings (e.g., :m5 or "m5").
The 1 is optional: D1 = D, h1 = h, etc...
| Pattern | Description | Examples |
|---|---|---|
:ticks | Raw tick data | ticks |
t<N> | N ticks per bar | t5, t100 |
s<N> | N-second bars | s30 |
m<N> | N-minute bars | m1, m5, m15, m30 |
h<N> | N-hour bars | h1, h4 |
D<N> | N-day bars | D, D3 |
W<N> | N-week bars | W |
M<N> | N-month bars | M |
Tips and Best Practices
Use Caching
Enable caching to avoid redundant downloads:
Dukascopy.stream("EUR/USD", :h1,
from: ~D[2024-01-01],
to: ~D[2024-06-30],
use_cache: true
)dukascopy download -i EUR/USD -t h1 --from 2024-01-01 --to 2024-06-30 --cacheStart with Higher Timeframes
Start with higher timeframes for faster prototyping, then move to lower timeframes for more precise data:
# Fast iteration during development
Dukascopy.stream("EUR/USD", :D, from: ~D[2020-01-01], to: ~D[2024-01-01])
# Switch to detailed data for final testing
Dukascopy.stream("EUR/USD", :m1, from: ~D[2024-01-01], to: ~D[2024-03-01])# Fast iteration during development
dukascopy download -i EUR/USD -t D --from 2020-01-01 --to 2024-01-01
# Switch to detailed data for final testing
dukascopy download -i EUR/USD -t m1 --from 2024-01-01 --to 2024-03-01Handle Market Hours
Forex markets close on weekends. Your data will have gaps from Friday evening to Sunday evening.
Next Steps
- Understanding DataFeeds - Learn about DataFeed concepts
- Visualization with Kino - Visualize your downloaded data