diff --git a/.gitignore b/.gitignore index 94d18c2a..854da391 100644 --- a/.gitignore +++ b/.gitignore @@ -135,3 +135,13 @@ fastquant_0.0.0.9000.tar.gz # VSCode Workspace files *.code-workspace + +# PyCharm Workspace files +*.idea/ + +# tmp pickle test files +*.pickle + +# tmp forex data +/python/fastquant/data/*.txt +/python/fastquant/data/*.zip diff --git a/README.md b/README.md index 8aa66999..2da01ae9 100644 --- a/README.md +++ b/README.md @@ -8,11 +8,13 @@ **fastquant** allows you to easily backtest investment strategies with as few as 3 lines of python code. Its goal is to promote data driven investments by making quantitative analysis in finance accessible to everyone. ## Features -1. Easily access historical stock data +1. Easily access historical stock and forex data 2. Backtest and optimize trading strategies with only 3 lines of code `*` - Both Yahoo Finance and Philippine stock data data are accessible straight from fastquant +`*` - Support one minute foreign exchange data from Forextester.com and conversion to other time period + Check out our blog posts in the fastquant [website](https://enzoampil.github.io/fastquant-blog/) and this intro [article](https://towardsdatascience.com/backtest-your-trading-strategy-with-only-3-lines-of-python-3859b4a4ab44?source=friends_link&sk=ec647b6bb43fe322013248fd1d473015) on Medium! ## Installation @@ -110,6 +112,39 @@ get_crypto_data("BTCUSDT", "2019-01-01", "2019-03-01") *R does NOT have support for backtesting yet* +## Get forex data + +All symbols from [forextester.com](https://forextester.com/) are accessible via `get_forex_data`.This method fetch one minute data from source and convert it to other time period, M1, M15, H1, D1, W1 are supported time period now. + +### Python +First, call `get_forex_data` with the following parameters: +``` +from fastquant import get_forex_data +df = get_forex_data('EURUSD', period='D1', read_from_local=False) +print(df) + dt open high low close + 2001-01-02 23:01:00 0.9507 0.9509 0.9505 0.9507 + 2001-01-03 00:00:00 0.9506 0.9569 0.9262 0.9283 + 2001-01-04 00:00:00 0.9283 0.9536 0.9283 0.9532 + 2001-01-05 00:00:00 0.9532 0.9591 0.9464 0.9583 + 2001-01-07 23:02:00 0.9583 0.9585 0.9576 0.9584 + ... ... ... ... ... + 2020-08-25 00:00:00 1.1792 1.1841 1.1784 1.1833 + 2020-08-26 00:00:00 1.1833 1.1839 1.1772 1.1839 + 2020-08-27 00:00:00 1.1839 1.1895 1.1767 1.1819 + 2020-08-28 00:00:00 1.1819 1.1918 1.1810 1.1906 + 2020-08-30 22:00:00 1.1906 1.1918 1.1901 1.1916 +[6127 rows x 5 columns] +``` +this process download online data, transfer it, save cache files in disk, first call will need 20 minutes or more and 2.3GB free RAM to generate cache files. + +After then, set `read_from_local=Ture` and you will get a second response if don't need update local data to newest. + +### R + +``` +pass +``` ## Backtest trading strategies *Note: Support for backtesting in R is pending* diff --git a/python/fastquant/data/__init__.py b/python/fastquant/data/__init__.py index 12cb1ab6..eca5535a 100644 --- a/python/fastquant/data/__init__.py +++ b/python/fastquant/data/__init__.py @@ -25,3 +25,6 @@ # Twitter from fastquant.data.web.twitter import tweepy_api from fastquant.data.web.twitter import get_twitter_sentiment + +# Forex +from fastquant.data.forex.forex import get_forex_data \ No newline at end of file diff --git a/python/fastquant/data/forex/__init__.py b/python/fastquant/data/forex/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/python/fastquant/data/forex/forex.py b/python/fastquant/data/forex/forex.py new file mode 100644 index 00000000..7e445a29 --- /dev/null +++ b/python/fastquant/data/forex/forex.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +import numpy as np + +# Import from config +from fastquant.config import DATA_FORMAT_COLS + +# Import package +from fastquant.data.forex.forextester import get_forextester_data, get_local_data + + +def get_forex_data(symbol, start_date=None, end_date=None, source="forextester", period='D1', read_from_local=False): + """Returns pricing data for a specified forex pair. + + Parameters + ---------- + symbol : str + Symbol of the forex in the forextester. + https://forextester.com/data/datasources + start_date : str + Starting date (YYYY-MM-DD) of the period that you want to get data on + in most cases we need more wide time period to test strategy, so keep this to None + end_date : str + Ending date (YYYY-MM-DD) of the period you want to get data on + in most cases we need more wide time period to test strategy, so keep this to None + source : str + Source of forex history data + period : str + time period you want, support 1 minute,15 minutes,1 hour,1 day,1 week + this parameter must one of them:["M1", "M15", "H1", "D1", "W1"] + read_from_local : bool + if this parameter set False, method get data from online + if set it to True, method get data from local pickle file, faster than set it to False + + Returns + ------- + pandas.DataFrame + """ + + if source == "forextester": + if read_from_local is False: + df = get_forextester_data(symbol, start_date, end_date, period) + else: + df = get_local_data(symbol, start_date, end_date, period) + else: + raise Exception("Source must be forextester") + + return df diff --git a/python/fastquant/data/forex/forextester.py b/python/fastquant/data/forex/forextester.py new file mode 100644 index 00000000..789e8237 --- /dev/null +++ b/python/fastquant/data/forex/forextester.py @@ -0,0 +1,479 @@ +from pathlib import Path +import zipfile +import logging +import pickle + +import requests +import pandas as pd +from pandas import DataFrame + +from fastquant.config import DATA_PATH +from fastquant.data.stocks.pse import datestring_to_datetime + +handler_format = logging.Formatter('%(asctime)s-%(name)s-%(levelname)s-%(message)s',datefmt='%Y-%m-%d %H:%M:%S') +logger = logging.getLogger('forex_logger') +logger_handler = logging.StreamHandler() +logger_handler.setFormatter(handler_format) +logger.setLevel(logging.INFO) +logger.addHandler(logger_handler) + +ALLOWED_SYMBOL_LIST = [ + 'AUDJPY', + 'AUDUSD', + 'CHFJPY', + 'EURCAD', + 'EURCHF', + 'EURGBP', + 'EURJPY', + 'EURUSD', + 'GBPCHF', + 'GBPJPY', + 'GBPUSD', + 'NZDJPY', + 'NZDUSD', + 'USDCAD', + 'USDJPY', + 'USDCHF', + 'XAGUSD', + 'XAUUSD' + ] + + +def download_and_unzip_data_from_forextester(symbol): + logger.info(f'start downloading forex {symbol} data zip file...') + file_size = 0 + res = requests.get(f'http://www.forextester.com/templates/data/files/{symbol}.zip', stream=True) + with open(Path(DATA_PATH, f'{symbol}.zip'), 'wb') as forex_zip_file: + for chunk in res.iter_content(chunk_size=4096): + file_size += 4096 + forex_zip_file.write(chunk) + logger.info(f'download {symbol} success') + zip_file = zipfile.ZipFile(Path(DATA_PATH, f'{symbol}.zip')) + zip_file.extractall(Path(DATA_PATH)) + logger.info('unzip success') + +def load_data_from_text(symbol): + forex_df = pd.read_csv( + Path(DATA_PATH, f'{symbol}.txt'), + dtype={'': str, '