Skip to content

Commit

Permalink
Merge commit 'b2a20917101bc94a31d21047db130eb92e5b9787'
Browse files Browse the repository at this point in the history
* commit 'b2a20917101bc94a31d21047db130eb92e5b9787':
  Add timezone info to the file name.
  Fix variable name
  Update Help message
  Added travis
  Fix unit tests
  Add local time Fix giuse88#18
  Fix candles help string issue giuse88#17

# Conflicts:
#	.travis.yml
#	README.md
#	duka/app/app.py
#	duka/core/csv_dumper.py
#	duka/core/processor.py
#	duka/main.py
#	requirements.txt
  • Loading branch information
thomasf1 committed Dec 9, 2019
2 parents 8c1dce5 + b2a2091 commit f0c3807
Show file tree
Hide file tree
Showing 8 changed files with 27 additions and 15 deletions.
2 changes: 0 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,3 @@ python:
install:
- pip install -r requirements.txt
script: make test
notifications:
email: false
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# duka - Dukascopy data downloader [![Build Status](https://travis-ci.org/giuse88/duka.svg?branch=master)](https://travis-ci.org/giuse88/duka)
# duka - Dukascopy data downloader

Finding good Forex data is difficult or expensive. Dukascopy has made available an excellent [web tool](https://www.dukascopy.com/swiss/english/marketwatch/historical/) to download tick data for a large a variety of
Forex, CFD and commodities. This is awesome and extremely useful for people, like me, trying to study the Forex market.
Expand Down Expand Up @@ -48,6 +48,7 @@ pip install duka
-f FOLDER the dowloaded data will be saved in FOLDER (default '.')
-t THREAD number of threads (default 10)
--header include CSV header (default false)
--local-time use local time (default GMT)
```

## Examples
Expand Down
6 changes: 3 additions & 3 deletions duka/app/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ def avg(fetch_times):
return -1


def app(symbols, start, end, throtteling, timeframes, folder, header):
def app(symbols, start, end, throtteling, timeframes, folder, header, local_time):
threads = 10

if start > end:
Expand All @@ -72,7 +72,7 @@ def do_work(symbol, day, csv):
star_time = time.time()
Logger.info("Fetching day {0}".format(day))
try:
csv.append(day, decompress(symbol, day, fetch_day(symbol, day)))
csv.append(day, decompress(symbol, local_time, day, fetch_day(symbol, day)))
except Exception as e:
print("ERROR for {0}, {1} Exception : {2}".format(day, symbol, str(e)))
elapsed_time = time.time() - star_time
Expand All @@ -85,7 +85,7 @@ def do_work(symbol, day, csv):

with concurrent.futures.ThreadPoolExecutor(max_workers=threads) as executor:

files = {symbol: CSVDumper(symbol, timeframes, start, end, folder, header) for symbol in symbols}
files = {symbol: CSVDumper(symbol, timeframes, start, end, folder, header, local_time) for symbol in symbols}

for symbol in symbols:
for day in days(start, end):
Expand Down
11 changes: 9 additions & 2 deletions duka/core/csv_dumper.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,15 @@ def write_candle(writer, candle):


class CSVDumper:
def __init__(self, symbol, timeframes, start, end, folder, header=False):
def __init__(self, symbol, timeframe, start, end, folder, header=False, local_time=False):
self.symbol = symbol
self.timeframes = timeframes
self.start = start
self.end = end
self.folder = folder
self.include_header = header
self.buffers = {}
self.local_time = local_time
for timeframe in timeframes:
self.buffers[timeframe] = {}

Expand Down Expand Up @@ -82,14 +83,20 @@ def append(self, day, ticks):
if timeframe != TimeFrame.TICK and len(ticks) != 0:
self.buffers[timeframe][day].append(Candle(self.symbol, previous_key, timeframe, current_ticks))

def get_timezone(self):
if self.local_time:
return "local_time"
else:
return "GMT"

def dump(self):
# For each timeseries
for timeframe in self.timeframes:

# The file name format
file_name = TEMPLATE_FILE_NAME.format(self.symbol,
self.start.year, self.start.month, self.start.day,
self.end.year, self.end.month, self.end.day, timeframe)
self.end.year, self.end.month, self.end.day, self.get_timezone())

Logger.info("Writing {0}".format(file_name))

Expand Down
14 changes: 9 additions & 5 deletions duka/core/processor.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import struct
from datetime import timedelta, datetime
from dateutil import tz
from lzma import LZMADecompressor, LZMAError, FORMAT_AUTO
from .utils import is_dst

Expand Down Expand Up @@ -57,19 +58,22 @@ def add_hour(ticks):
return ticks


def normalize(symbol, day, ticks):
def normalize(day, local_time, ticks):
def norm(time, ask, bid, volume_ask, volume_bid):
date = datetime(day.year, day.month, day.day) + timedelta(milliseconds=time)
# date.replace(tzinfo=datetime.tzinfo("UTC"))
if local_time:
date.replace(tzinfo=tz.tzlocal())

point = 100000
if symbol.lower() in ['usdrub', 'xagusd', 'xauusd']:
point = 1000
return date, ask / point, bid / point, round(volume_ask * 1000000), round(volume_bid * 1000000)

return date, ask / 100000, bid / 100000, round(volume_ask * 1000000), round(volume_bid * 1000000)

return add_hour(list(map(lambda x: norm(*x), ticks)))


def decompress(symbol, day, compressed_buffer):
def decompress(day, local_time, compressed_buffer):
if compressed_buffer.nbytes == 0:
return compressed_buffer
return normalize(symbol, day, tokenize(decompress_lzma(compressed_buffer)))
return normalize(day, local_time, tokenize(decompress_lzma(compressed_buffer)))
3 changes: 2 additions & 1 deletion duka/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ def main():
help='One or multiple Time frames to export. Example: TICK,H1. Accepted values: TICK M1 M2 M5 M10 M15 M30 H1 H4',
default=[TimeFrame.TICK])
parser.add_argument('--header', action='store_true', help='include CSV header (default false)', default=False)
parser.add_argument('--local-time', action='store_true', help='use local time (default GMT)', default=False)
args = parser.parse_args()

if args.startdate is not None:
Expand All @@ -39,7 +40,7 @@ def main():
end = args.day

set_up_signals()
app(args.symbols, start, end, args.throtteling, args.timeframes, args.folder, args.header)
app(args.symbols, start, end, args.throtteling, args.timeframes, args.folder, args.header, args.local_time)


if __name__ == '__main__':
Expand Down
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
requests>=2.9.1
python-dateutil
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
setup(
name=NAME,
packages=find_packages(),
install_requires=['requests>=2.9.1'],
install_requires=['requests>=2.9.1', 'python-dateutil'],
version=VERSION,
description='Dukascopy Bank SA historical data downloader',
author='Giuseppe Pes',
Expand Down

0 comments on commit f0c3807

Please sign in to comment.