├── test ├── __init__.py └── test_test.py ├── src ├── helper_functions.py ├── io_helper.py ├── example_helper.py ├── datetime_helper.py ├── data_model.py ├── data_loader_helper.py ├── load_augmento_data_helper.py └── analysis_helper.py ├── requirements.txt ├── documentation ├── simple_strategy_backtest_example.png └── simple_strategy_backtest_example_incorrect.png ├── setup.py ├── augmento_client ├── __init__.py ├── logging.ini └── rest_api.py ├── LICENSE ├── README.md ├── .gitignore ├── examples ├── 3_plot_augmento_example_data.py ├── 1_load_augmento_example_info.py ├── 0_load_augmento_example_data.py ├── 5_write_strategy_to_csv.py ├── 4_basic_strategy_example.py └── 2_load_bitmex_example_data.py └── notebooks └── 2_moving_windows.ipynb /test/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/helper_functions.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | requests 2 | msgpack 3 | numpy 4 | matplotlib 5 | pprint 6 | numba -------------------------------------------------------------------------------- /documentation/simple_strategy_backtest_example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/augmento-ai/quant-reseach/HEAD/documentation/simple_strategy_backtest_example.png -------------------------------------------------------------------------------- /documentation/simple_strategy_backtest_example_incorrect.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/augmento-ai/quant-reseach/HEAD/documentation/simple_strategy_backtest_example_incorrect.png -------------------------------------------------------------------------------- /test/test_test.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | class TestBasicFunction(unittest.TestCase): 4 | 5 | def setUp(self): 6 | pass 7 | 8 | def test_0(self): 9 | self.assertTrue(1 == 1) 10 | 11 | if __name__ == '__main__': 12 | unittest.main() -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # coding: utf-8 3 | # @Author: ArthurBernard 4 | # @Email: arthur.bernard.92@gmail.com 5 | # @Date: 2019-07-22 15:50:05 6 | # @Last modified by: ArthurBernard 7 | # @Last modified time: 2019-07-23 15:19:50 8 | 9 | # Built-in packages 10 | from setuptools import setup, find_packages 11 | 12 | # External packages 13 | 14 | # Local packages 15 | 16 | # TODO : add info parameters 17 | setup( 18 | name='augmento_client', 19 | packages=find_packages(), 20 | ) 21 | -------------------------------------------------------------------------------- /augmento_client/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # coding: utf-8 3 | # @Author: ArthurBernard 4 | # @Email: arthur.bernard.92@gmail.com 5 | # @Date: 2019-07-22 15:12:28 6 | # @Last modified by: ArthurBernard 7 | # @Last modified time: 2019-07-23 15:51:05 8 | 9 | """ Client connector to Augmento API. 10 | 11 | TODO : - websocket api. 12 | 13 | """ 14 | 15 | # Built-in packages 16 | 17 | # External packages 18 | 19 | # Local packages 20 | from augmento_client import rest_api 21 | from augmento_client.rest_api import * 22 | 23 | __all__ = rest_api.__all__ 24 | -------------------------------------------------------------------------------- /src/io_helper.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | def check_path(path, create_if_not_exist=True): 4 | if not os.path.exists(path) and create_if_not_exist == True: 5 | os.makedirs(path) 6 | return True 7 | elif not os.path.exists(path) and create_if_not_exist == False: 8 | return False 9 | 10 | def list_files_in_path_os(path, filename_prefix="", filename_suffix="", recursive=True): 11 | while path[-1] == "/": 12 | path = path[:-1] 13 | all_files = [] 14 | for (dirpath, dirnames, fname) in os.walk(path): 15 | all_files.extend([dirpath + "/" + el for el in fname if filename_prefix in el and filename_suffix in el]) 16 | if recursive == False: 17 | break 18 | all_files = sorted(all_files) 19 | return all_files -------------------------------------------------------------------------------- /augmento_client/logging.ini: -------------------------------------------------------------------------------- 1 | version: 1 2 | 3 | formatters: 4 | simple: 5 | format: '%(asctime)s | %(levelname)s | %(name)s | %(message)s' 6 | 7 | handlers: 8 | console: 9 | class: logging.StreamHandler 10 | level: DEBUG 11 | formatter: simple 12 | stream: ext://sys.stdout 13 | error_file: 14 | class : logging.handlers.RotatingFileHandler 15 | level: ERROR 16 | formatter: simple 17 | filename: augmento_client/errors.log 18 | maxBytes: 1048576 19 | backupCount: 3 20 | encoding: utf8 21 | 22 | loggers: 23 | get_augmento_data: 24 | level: DEBUG 25 | handlers: [console, error_file] 26 | propagate: no 27 | 28 | root: 29 | level: DEBUG 30 | handlers: [console, error_file] 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 augmento-ai 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 |

4 | 5 | # Quant Reseach 6 | 7 | This repo serves as a quickstart guide for using using Augmento sentiment data, as well as a working repo for analysing the data and developing example strategies. 8 | 9 | Augmento API docs: http://api-dev.augmento.ai/v0.1/documentation 10 | 11 | Bitmex API docs: https://www.bitmex.com/api/explorer/ 12 | 13 | ## Getting started 14 | 15 | Prerequisites 16 | 17 | python 2.7 or later 18 | 19 | Install requirements 20 | 21 | pip install -r requirements.txt --user 22 | zlib (already included with MacOS) 23 | 24 | Run tests 25 | 26 | python -m unittest discover -v 27 | 28 | ## Examples 29 | 30 | ### Quickstart 31 | 32 | The quickstart examples are the quickest way to download some data, plot the data, and run a simple strategy. 33 | 34 | Cache two years of Augmento data from the Augmento ReST API to a local folder 35 | 36 | python examples/0_load_augmento_example_data.py 37 | 38 | Cache a list of sources, coins, bin sizes, and topics from the Augmento ReST API to a local folder 39 | 40 | python examples/1_load_augmento_example_info.py 41 | 42 | Cache two years of XBt candle data from the Bitmex ReST API to a local folder (this may take a few minutes) 43 | 44 | python examples/2_load_bitmex_example_data.py 45 | 46 | Plot some of the cached raw Augmento data against the cached Bitmex XBt price data 47 | 48 | python examples/3_plot_augmento_example_data.py 49 | 50 | Backtest a very simple strategy using Augmento data against the Bitmex XBt price, and plot the results 51 | 52 | python examples/4_basic_strategy_example.py 53 | 54 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | data/ 3 | 4 | # Byte-compiled / optimized / DLL files 5 | __pycache__/ 6 | *.py[cod] 7 | *$py.class 8 | 9 | # C extensions 10 | *.so 11 | 12 | # Distribution / packaging 13 | .Python 14 | build/ 15 | develop-eggs/ 16 | dist/ 17 | downloads/ 18 | eggs/ 19 | .eggs/ 20 | lib/ 21 | lib64/ 22 | parts/ 23 | sdist/ 24 | var/ 25 | wheels/ 26 | *.egg-info/ 27 | .installed.cfg 28 | *.egg 29 | MANIFEST 30 | 31 | # PyInstaller 32 | # Usually these files are written by a python script from a template 33 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 34 | *.manifest 35 | *.spec 36 | 37 | # Installer logs 38 | pip-log.txt 39 | pip-delete-this-directory.txt 40 | 41 | # Unit test / coverage reports 42 | htmlcov/ 43 | .tox/ 44 | .coverage 45 | .coverage.* 46 | .cache 47 | nosetests.xml 48 | coverage.xml 49 | *.cover 50 | .hypothesis/ 51 | .pytest_cache/ 52 | 53 | # Translations 54 | *.mo 55 | *.pot 56 | 57 | # Django stuff: 58 | *.log 59 | local_settings.py 60 | db.sqlite3 61 | 62 | # Flask stuff: 63 | instance/ 64 | .webassets-cache 65 | 66 | # Scrapy stuff: 67 | .scrapy 68 | 69 | # Sphinx documentation 70 | docs/_build/ 71 | 72 | # PyBuilder 73 | target/ 74 | 75 | # Jupyter Notebook 76 | .ipynb_checkpoints 77 | 78 | # pyenv 79 | .python-version 80 | 81 | # celery beat schedule file 82 | celerybeat-schedule 83 | 84 | # SageMath parsed files 85 | *.sage.py 86 | 87 | # Environments 88 | .env 89 | .venv 90 | env/ 91 | venv/ 92 | ENV/ 93 | env.bak/ 94 | venv.bak/ 95 | 96 | # Spyder project settings 97 | .spyderproject 98 | .spyproject 99 | 100 | # Rope project settings 101 | .ropeproject 102 | 103 | # mkdocs documentation 104 | /site 105 | 106 | # mypy 107 | .mypy_cache/ 108 | -------------------------------------------------------------------------------- /examples/3_plot_augmento_example_data.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import msgpack 3 | import zlib 4 | import numpy as np 5 | import datetime 6 | import matplotlib.pyplot as plt 7 | import matplotlib.dates as md 8 | 9 | # import files from src 10 | sys.path.insert(0, "src") 11 | import example_helper as eh 12 | 13 | # define the location of the input file 14 | filename_augmento_topics = "data/example_data/augmento_topics.msgpack.zlib" 15 | filename_augmento_data = "data/example_data/augmento_data.msgpack.zlib" 16 | filename_bitmex_data = "data/example_data/bitmex_data.msgpack.zlib" 17 | 18 | # load the example data 19 | all_data = eh.load_example_data(filename_augmento_topics, 20 | filename_augmento_data, 21 | filename_bitmex_data) 22 | aug_topics, aug_topics_inv, t_aug_data, aug_data, t_price_data, price_data = all_data 23 | 24 | # get the signals we're interested in 25 | aug_signal_a = aug_data[:, aug_topics_inv["Bullish"]] 26 | aug_signal_b = aug_data[:, aug_topics_inv["Bearish"]] 27 | 28 | # set up the figure 29 | fig, ax = plt.subplots(2, 1, sharex=True, sharey=False) 30 | 31 | # initialise some labels for the plot 32 | datenum_aug_data = [md.date2num(datetime.datetime.fromtimestamp(el)) for el in t_aug_data] 33 | datenum_price_data = [md.date2num(datetime.datetime.fromtimestamp(el)) for el in t_price_data] 34 | 35 | # plot stuff 36 | ax[0].grid(linewidth=0.4) 37 | ax[1].grid(linewidth=0.4) 38 | ax[0].plot(datenum_price_data, price_data, linewidth=0.5) 39 | ax[1].plot(datenum_aug_data, aug_signal_a, color="g", linewidth=0.5) 40 | ax[1].plot(datenum_aug_data, aug_signal_b, color="r", linewidth=0.5) 41 | #ax[1].plot(datenum_aug_data, aug_data, linewidth=0.5) 42 | 43 | # label axes 44 | ax[0].set_ylabel("Price") 45 | ax[1].set_ylabel("Seniments") 46 | ax[1].legend(["Bullish", "Bearish"]) 47 | 48 | # generate the time axes 49 | plt.subplots_adjust(bottom=0.2) 50 | plt.xticks( rotation=25 ) 51 | ax[0]=plt.gca() 52 | xfmt = md.DateFormatter('%Y-%m-%d %H:%M') 53 | ax[0].xaxis.set_major_formatter(xfmt) 54 | 55 | # show the plot 56 | plt.show() 57 | 58 | 59 | -------------------------------------------------------------------------------- /examples/1_load_augmento_example_info.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import requests 3 | import datetime 4 | import time 5 | import zlib 6 | import msgpack 7 | 8 | # import files from src 9 | sys.path.insert(0, "src") 10 | import helper_functions as hf 11 | import io_helper as ioh 12 | 13 | # define the urls of the endpoints for all the info 14 | topics_endpoint_url = "http://api-dev.augmento.ai/v0.1/topics" 15 | sources_endpoint_url = "http://api-dev.augmento.ai/v0.1/sources" 16 | coins_endpoint_url = "http://api-dev.augmento.ai/v0.1/coins" 17 | bin_sizes_endpoint_url = "http://api-dev.augmento.ai/v0.1/bin_sizes" 18 | 19 | # define where we're going to save the data 20 | path_save_data = "data/example_data" 21 | filename_save_topics = "{:s}/augmento_topics.msgpack.zlib".format(path_save_data) 22 | filename_save_sources = "{:s}/augmento_sources.msgpack.zlib".format(path_save_data) 23 | filename_save_coins = "{:s}/augmento_coins.msgpack.zlib".format(path_save_data) 24 | filename_save_bin_sizes = "{:s}/augmento_bin_sizes.msgpack.zlib".format(path_save_data) 25 | 26 | # check if the data path exists 27 | ioh.check_path(path_save_data, create_if_not_exist=True) 28 | 29 | # save a list of the augmento topics 30 | r = requests.request("GET", topics_endpoint_url, timeout=10) 31 | print("saving topics to {:s}".format(filename_save_topics)) 32 | with open(filename_save_topics, "wb") as f: 33 | f.write(zlib.compress(msgpack.packb(r.json()))) 34 | 35 | # save a list of the augmento topics 36 | r = requests.request("GET", sources_endpoint_url, timeout=10) 37 | print("saving sources to {:s}".format(filename_save_sources)) 38 | with open(filename_save_sources, "wb") as f: 39 | f.write(zlib.compress(msgpack.packb(r.json()))) 40 | 41 | # save a list of the augmento topics 42 | r = requests.request("GET", coins_endpoint_url, timeout=10) 43 | print("saving coins to {:s}".format(filename_save_coins)) 44 | with open(filename_save_coins, "wb") as f: 45 | f.write(zlib.compress(msgpack.packb(r.json()))) 46 | 47 | # save a list of the augmento topics 48 | r = requests.request("GET", bin_sizes_endpoint_url, timeout=10) 49 | print("saving bin_sizes to {:s}".format(filename_save_bin_sizes)) 50 | with open(filename_save_bin_sizes, "wb") as f: 51 | f.write(zlib.compress(msgpack.packb(r.json()))) 52 | 53 | 54 | print("done!") 55 | 56 | -------------------------------------------------------------------------------- /src/example_helper.py: -------------------------------------------------------------------------------- 1 | import msgpack 2 | import zlib 3 | import numpy as np 4 | import helper_functions as hf 5 | import datetime_helper as dh 6 | 7 | def strip_data_by_time(t_data, data, t_min, t_max): 8 | data = np.array([s for s, t in zip(data, t_data) if t >= t_min and t <= t_max]) 9 | t_data = np.array([t for t in t_data if t >= t_min and t <= t_max]) 10 | return t_data, data 11 | 12 | def load_example_data(filename_augmento_topics, 13 | filename_augmento_data, 14 | filename_bitmex_data, 15 | datetime_start=None, 16 | datetime_end=None): 17 | 18 | # load the topics 19 | with open(filename_augmento_topics, "rb") as f: 20 | temp = msgpack.unpackb(zlib.decompress(f.read()), encoding='utf-8') 21 | augmento_topics = {int(k) : v for k, v in temp.items()} 22 | augmento_topics_inv = {v : int(k) for k, v in temp.items()} 23 | 24 | # load the augmento data 25 | with open(filename_augmento_data, "rb") as f: 26 | temp = msgpack.unpackb(zlib.decompress(f.read()), encoding='utf-8') 27 | t_aug_data = np.array([el["t_epoch"] for el in temp], dtype=np.float64) 28 | aug_data = np.array([el["counts"] for el in temp], dtype=np.int32) 29 | 30 | # load the price data 31 | with open(filename_bitmex_data, "rb") as f: 32 | temp = msgpack.unpackb(zlib.decompress(f.read()), encoding='utf-8') 33 | t_price_data = np.array([el["t_epoch"] for el in temp], dtype=np.float64) 34 | #price_data = np.array([el["open"] for el in temp], dtype=np.float64) 35 | price_data = np.array([el["close"] for el in temp], dtype=np.float64) 36 | 37 | # set the start and end times if they are specified 38 | if datetime_start != None: 39 | t_start = dh.datetime_to_epoch(datetime_start) 40 | else: 41 | t_start = max(np.min(t_aug_data), np.min(t_price_data)) 42 | 43 | if datetime_end != None: 44 | t_end = dh.datetime_to_epoch(datetime_end) 45 | else: 46 | t_end = min(np.max(t_aug_data), np.max(t_price_data)) 47 | 48 | # strip the sentiments and prices outside the shared time range 49 | t_aug_data, aug_data = strip_data_by_time(t_aug_data, aug_data, t_start, t_end) 50 | t_price_data, price_data = strip_data_by_time(t_price_data, price_data, t_start, t_end) 51 | 52 | return augmento_topics, augmento_topics_inv, t_aug_data, aug_data, t_price_data, price_data 53 | -------------------------------------------------------------------------------- /examples/0_load_augmento_example_data.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import requests 3 | import datetime 4 | import time 5 | import zlib 6 | import msgpack 7 | 8 | # import files from src 9 | sys.path.insert(0, "src") 10 | import helper_functions as hf 11 | import io_helper as ioh 12 | 13 | # define the url of the endpoint to get event data 14 | endpoint_url = "http://api-dev.augmento.ai/v0.1/events/aggregated" 15 | 16 | # define where we're going to save the data 17 | path_save_data = "data/example_data" 18 | filename_save_data = "{:s}/augmento_data.msgpack.zlib".format(path_save_data) 19 | 20 | # define the start and end times 21 | datetime_start = datetime.datetime(2017, 1, 1) 22 | datetime_end = datetime.datetime(2019, 9, 25) 23 | 24 | # initialise a store for the data we're downloading 25 | sentiment_data = [] 26 | 27 | # define a start pointer to track multiple requests 28 | start_ptr = 0 29 | count_ptr = 1000 30 | 31 | # get the data 32 | while start_ptr >= 0: 33 | 34 | # define the parameters of the request 35 | params = { 36 | "source" : "twitter", 37 | "coin" : "bitcoin", 38 | "bin_size" : "1H", 39 | "count_ptr" : count_ptr, 40 | "start_ptr" : start_ptr, 41 | "start_datetime" : datetime_start.strftime("%Y-%m-%dT%H:%M:%SZ"), 42 | "end_datetime" : datetime_end.strftime("%Y-%m-%dT%H:%M:%SZ"), 43 | } 44 | 45 | # make the request 46 | r = requests.request("GET", endpoint_url, params=params, timeout=10) 47 | 48 | # if the request was ok, add the data and increment the start_ptr 49 | # else return an error 50 | if r.status_code == 200: 51 | temp_data = r.json() 52 | start_ptr += count_ptr 53 | else: 54 | raise Exception("api call failed with status_code {:d}".format(r.status_code)) 55 | 56 | # if we didn't get any data, assume we've got all the data 57 | if len(temp_data) == 0: 58 | start_ptr = -1 59 | 60 | # extend the data store 61 | sentiment_data.extend(temp_data) 62 | 63 | # print the progress 64 | str_print = "got data from {:s} to {:s}".format(*(sentiment_data[0]["datetime"], 65 | sentiment_data[-1]["datetime"],)) 66 | print(str_print) 67 | 68 | # sleep 69 | time.sleep(2.0) 70 | 71 | # check if the data path exists 72 | ioh.check_path(path_save_data, create_if_not_exist=True) 73 | 74 | # save the data 75 | print("saving data to {:s}".format(filename_save_data)) 76 | with open(filename_save_data, "wb") as f: 77 | f.write(zlib.compress(msgpack.packb(sentiment_data))) 78 | 79 | 80 | print("done!") 81 | 82 | -------------------------------------------------------------------------------- /src/datetime_helper.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | import io_helper as ioh 3 | 4 | # set the utc value of the epoch 5 | epoch = datetime.datetime.utcfromtimestamp(0) 6 | 7 | def date_str_to_seconds(date_str, format): 8 | return (datetime.datetime.strptime(date_str, format) - datetime.datetime(1970,1,1)).total_seconds() 9 | 10 | def datetime_str_to_datetime(date_str, timestamp_format_str="%Y-%m-%d %H:%M:%S"): 11 | return datetime.datetime.strptime(date_str, timestamp_format_str) 12 | 13 | def timestamp_to_epoch(timestamp_str, timestamp_format_str): 14 | return (datetime.datetime.strptime(timestamp_str, timestamp_format_str) - epoch).total_seconds() 15 | 16 | def epoch_to_datetime(t_epoch): 17 | # must be UTC to remove timezone 18 | return datetime.datetime.utcfromtimestamp(t_epoch) 19 | 20 | def epoch_to_datetime_str(t_epoch, timestamp_format_str="%Y-%m-%d %H:%M:%S"): 21 | # must be UTC to remove timezone 22 | return datetime.datetime.utcfromtimestamp(t_epoch).strftime(timestamp_format_str) 23 | 24 | def datetime_to_str(datetime_a, timestamp_format_str="%Y-%m-%d %H:%M:%S"): 25 | # must be UTC to remove timezone 26 | return datetime_a.strftime(timestamp_format_str) 27 | 28 | def round_datetime_to_day_start(datetime_a, forward_days=0): 29 | datetime_a = datetime_a.replace(hour=0, minute=0, second=0, microsecond=0) 30 | return add_days_to_datetime(datetime_a, forward_days) 31 | 32 | def add_days_to_datetime(datetime_a, forward_days): 33 | return datetime_a + datetime.timedelta(days=forward_days) 34 | 35 | def datetime_to_epoch(datetime_a): 36 | return (datetime_a - epoch).total_seconds() 37 | 38 | def timestamp_to_datetime(timestamp_str, timestamp_format_str): 39 | return datetime.datetime.strptime(timestamp_str, timestamp_format_str) 40 | 41 | def list_file_dates_for_path(path, filename_suffix, datetime_format_str): 42 | date_strs = ioh.list_files_in_path_os(path, filename_suffix=filename_suffix) 43 | date_strs = [el.split("/")[-1].replace(filename_suffix, "") for el in date_strs] 44 | dates = [datetime_str_to_datetime(el, timestamp_format_str=datetime_format_str) 45 | for el in date_strs] 46 | return dates 47 | 48 | def get_datetimes_between_datetimes(datetime_start, datetime_end): 49 | #return [datetime_start + datetime.timedelta(days=x) 50 | # for x in range(0, (datetime_end-datetime_start).days + 1)] 51 | round_datetime_start = round_datetime_to_day_start(datetime_start) 52 | round_datetime_end = round_datetime_to_day_start(datetime_end) 53 | return [round_datetime_start + datetime.timedelta(days=x) 54 | for x in range(0, (round_datetime_end-round_datetime_start).days + 1)] 55 | -------------------------------------------------------------------------------- /examples/5_write_strategy_to_csv.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import msgpack 3 | import zlib 4 | import numpy as np 5 | import pandas as pd 6 | import datetime 7 | import matplotlib.pyplot as plt 8 | import matplotlib.dates as md 9 | 10 | # import files from src 11 | sys.path.insert(0, "src") 12 | import example_helper as eh 13 | import analysis_helper as ah 14 | 15 | # define the location of the input file 16 | filename_augmento_topics = "data/example_data/augmento_topics.msgpack.zlib" 17 | filename_augmento_data = "data/example_data/augmento_data.msgpack.zlib" 18 | filename_bitmex_data = "data/example_data/bitmex_data.msgpack.zlib" 19 | 20 | # load the example data 21 | all_data = eh.load_example_data(filename_augmento_topics, filename_augmento_data, filename_bitmex_data) 22 | aug_topics, aug_topics_inv, t_aug_data, aug_data, t_price_data, price_data = all_data 23 | 24 | 25 | 26 | # get the signals we're interested in 27 | aug_signal_a = aug_data[:, aug_topics_inv["Positive"]].astype(np.float64) 28 | aug_signal_b = aug_data[:, aug_topics_inv["Bearish"]].astype(np.float64) 29 | 30 | sent_score = ah.nb_calc_sentiment_score_c(aug_signal_a, aug_signal_b, 28*24, 14*24) 31 | 32 | date_time = np.array([datetime.datetime.utcfromtimestamp(t).isoformat() 33 | for t in t_price_data]) 34 | 35 | # define some parameters for the backtest 36 | start_pnl = 1.0 37 | buy_sell_fee = 0.00075 38 | # run the backtest 39 | pnl = ah.nb_backtest_a(price_data, sent_score, start_pnl, buy_sell_fee) 40 | # set up the figure 41 | fig, ax = plt.subplots(3, 1, sharex=True, sharey=False) 42 | # initialise some labels for the plot 43 | datenum_aug_data = [md.date2num(datetime.datetime.fromtimestamp(el)) for el in t_aug_data] 44 | datenum_price_data = [md.date2num(datetime.datetime.fromtimestamp(el)) for el in t_price_data] 45 | # plot stuff 46 | ax[0].grid(linewidth=0.4) 47 | ax[1].grid(linewidth=0.4) 48 | ax[2].grid(linewidth=0.4) 49 | ax[0].plot(datenum_price_data, price_data, linewidth=0.5) 50 | ax[1].plot(datenum_aug_data, sent_score, linewidth=0.5) 51 | ax[2].plot(datenum_price_data, pnl, linewidth=0.5) 52 | # label axes 53 | ax[0].set_ylabel("Price") 54 | ax[1].set_ylabel("Seniment score") 55 | ax[2].set_ylabel("PnL") 56 | #ax[0].set_title("4_basic_strategy_example.py") 57 | # generate the time axes 58 | plt.subplots_adjust(bottom=0.2) 59 | plt.xticks( rotation=25 ) 60 | ax[0]=plt.gca() 61 | xfmt = md.DateFormatter('%Y-%m-%d') 62 | ax[0].xaxis.set_major_formatter(xfmt) 63 | # show the plot 64 | plt.show() 65 | 66 | 67 | 68 | csv_data= {"date": date_time, "ref_price":price_data,"raw_signal":sent_score,"pnl":pnl} 69 | 70 | data_frame = pd.DataFrame(csv_data) 71 | 72 | data_frame.to_csv("data/signals.csv",index=False) 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /examples/4_basic_strategy_example.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import msgpack 3 | import zlib 4 | import numpy as np 5 | import datetime 6 | import matplotlib.pyplot as plt 7 | import matplotlib.dates as md 8 | 9 | # import files from src 10 | sys.path.insert(0, "src") 11 | import example_helper as eh 12 | import analysis_helper as ah 13 | 14 | # define the location of the input file 15 | filename_augmento_topics = "data/example_data/augmento_topics.msgpack.zlib" 16 | filename_augmento_data = "data/example_data/augmento_data.msgpack.zlib" 17 | filename_bitmex_data = "data/example_data/bitmex_data.msgpack.zlib" 18 | 19 | # load the example data 20 | all_data = eh.load_example_data(filename_augmento_topics, 21 | filename_augmento_data, 22 | filename_bitmex_data) 23 | aug_topics, aug_topics_inv, t_aug_data, aug_data, t_price_data, price_data = all_data 24 | 25 | # get the signals we're interested in 26 | aug_signal_a = aug_data[:, aug_topics_inv["Negative"]].astype(np.float64) 27 | aug_signal_b = aug_data[:, aug_topics_inv["Bearish"]].astype(np.float64) 28 | #aug_signal_b = aug_data[:, aug_topics_inv["Bullish"]].astype(np.float64) 29 | #aug_signal_a = aug_data[:, aug_topics_inv["Bearish"]].astype(np.float64) 30 | 31 | # define the window size for the sentiment score calculation 32 | n_days = 7 33 | window_size = 24 * n_days 34 | 35 | # generate the sentiment score 36 | sent_score = ah.nb_calc_sentiment_score_a(aug_signal_a, aug_signal_b, window_size, window_size) 37 | #sent_score = ah.nb_calc_sentiment_score_c(aug_signal_a, aug_signal_b, window_size, window_size) 38 | 39 | # define some parameters for the backtest 40 | start_pnl = 1.0 41 | buy_sell_fee = 0.0 42 | 43 | # run the backtest 44 | pnl = ah.nb_backtest_a(price_data, sent_score, start_pnl, buy_sell_fee) 45 | 46 | # set up the figure 47 | fig, ax = plt.subplots(3, 1, sharex=True, sharey=False) 48 | 49 | # initialise some labels for the plot 50 | datenum_aug_data = [md.date2num(datetime.datetime.fromtimestamp(el)) for el in t_aug_data] 51 | datenum_price_data = [md.date2num(datetime.datetime.fromtimestamp(el)) for el in t_price_data] 52 | 53 | # plot stuff 54 | ax[0].grid(linewidth=0.4) 55 | ax[1].grid(linewidth=0.4) 56 | ax[2].grid(linewidth=0.4) 57 | ax[0].plot(datenum_price_data, price_data, linewidth=0.5) 58 | ax[1].plot(datenum_aug_data, sent_score, linewidth=0.5) 59 | ax[2].plot(datenum_price_data, pnl, linewidth=0.5) 60 | 61 | # label axes 62 | ax[0].set_ylabel("Price") 63 | ax[1].set_ylabel("Seniment score") 64 | ax[2].set_ylabel("PnL") 65 | ax[1].set_ylim([-5.5, 5.5]) 66 | 67 | #ax[0].set_title("4_basic_strategy_example.py") 68 | 69 | # generate the time axes 70 | plt.subplots_adjust(bottom=0.2) 71 | plt.xticks( rotation=25 ) 72 | ax[0]=plt.gca() 73 | xfmt = md.DateFormatter('%Y-%m-%d') 74 | ax[0].xaxis.set_major_formatter(xfmt) 75 | 76 | # show the plot 77 | plt.show() 78 | -------------------------------------------------------------------------------- /examples/2_load_bitmex_example_data.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import requests 3 | import datetime 4 | import time 5 | import zlib 6 | import msgpack 7 | 8 | # import files from src 9 | sys.path.insert(0, "src") 10 | import helper_functions as hf 11 | import io_helper as ioh 12 | import datetime_helper as dh 13 | 14 | # define the url of the endpoint 15 | endpoint_url = "https://www.bitmex.com/api/v1/trade/bucketed" 16 | 17 | # define where we're going to save the data 18 | path_save_data = "data/example_data" 19 | filename_save_data = "{:s}/bitmex_data.msgpack.zlib".format(path_save_data) 20 | 21 | # define the start and end times 22 | datetime_start = datetime.datetime(2017, 1, 1) 23 | datetime_end = datetime.datetime(2019, 9, 25) 24 | 25 | # initialise a store for the data we're downloading 26 | market_data = [] 27 | 28 | # define a start pointer to track multiple requests 29 | start_ptr = 0 30 | count_ptr = 750 31 | 32 | # get the data 33 | while start_ptr >= 0: 34 | 35 | # bug in bitmex ptr system, need to shift the start date forward for each request 36 | if market_data == []: 37 | str_datetime_start = datetime_start.strftime("%Y-%m-%dT%H:%M:%SZ") 38 | start_ptr = 0 39 | else: 40 | str_datetime_start = market_data[-1]["timestamp"] 41 | start_ptr = 1 42 | 43 | # define the parameters of the request 44 | params = { 45 | "symbol" : "XBt", 46 | "binSize" : "1h", 47 | "count" : count_ptr, 48 | "start" : start_ptr, 49 | "startTime" : str_datetime_start, 50 | "endTime" : datetime_end.strftime("%Y-%m-%dT%H:%M:%SZ"), 51 | } 52 | 53 | # make the request 54 | r = requests.request("GET", endpoint_url, params=params, timeout=10) 55 | 56 | # if the request was ok, add the data and increment the start_ptr 57 | # else return an error 58 | if r.status_code == 200: 59 | temp_data = r.json() 60 | start_ptr += count_ptr 61 | else: 62 | raise Exception("api call failed with status_code {:d}".format(r.status_code)) 63 | 64 | # if we didn't get any data, assume we've got all the data 65 | # else add the data to the data store 66 | if len(temp_data) == 0: 67 | start_ptr = -1 68 | else: 69 | 70 | # convert the iso timestamps to epoch times 71 | for td in temp_data: 72 | t_epoch = dh.timestamp_to_epoch(td["timestamp"], "%Y-%m-%dT%H:%M:%S.000Z") 73 | td.update({"t_epoch" : t_epoch}) 74 | 75 | # extend the data store 76 | market_data.extend(temp_data) 77 | 78 | # print the progress 79 | str_print = "got data from {:s} to {:s}".format(*(temp_data[0]["timestamp"], 80 | temp_data[-1]["timestamp"],)) 81 | print(str_print) 82 | 83 | # sleep 84 | time.sleep(2.1) 85 | 86 | # check if the data path exists 87 | ioh.check_path(path_save_data, create_if_not_exist=True) 88 | 89 | # save the data 90 | print("saving data to {:s}".format(filename_save_data)) 91 | with open(filename_save_data, "wb") as f: 92 | f.write(zlib.compress(msgpack.packb(market_data))) 93 | 94 | print("done!") 95 | 96 | -------------------------------------------------------------------------------- /src/data_model.py: -------------------------------------------------------------------------------- 1 | import example_helper as eh 2 | import numpy as np 3 | import math 4 | 5 | 6 | 7 | # TODO: improve commenting 8 | 9 | class Data(): 10 | 11 | def __init__(self): 12 | 13 | pass 14 | 15 | def load_raw(self, 16 | augmento_topic = "data/example_data/augmento_topics.msgpack.zlib", 17 | augmento_data = "data/example_data/augmento_data.msgpack.zlib", 18 | bitmex_data = "data/example_data/bitmex_data.msgpack.zlib"): 19 | 20 | # load all raw data 21 | self.aug_topics, self.aug_topics_inv, self.t_aug_data,\ 22 | self.aug_data, self.t_price_data, self.price_data =\ 23 | eh.load_example_data(augmento_topic, augmento_data, bitmex_data) 24 | print("loaded") 25 | 26 | 27 | def get_data(self, n_timesteps, forward): 28 | 29 | # number of sentiments 30 | n_sentiments = self.aug_data.shape[1] 31 | 32 | # number of all data points 33 | n_data = self.aug_data.shape[0] 34 | 35 | # index of the last observation 36 | last_data = n_data - forward 37 | 38 | # number of all samples 39 | n_samples = last_data - n_timesteps + 1 40 | 41 | # create empty arrays for sentiment and price 42 | arr_aug = np.zeros((n_samples, n_timesteps, n_sentiments),dtype=np.float64) 43 | 44 | #arr_price = np.zeros(n_samples) 45 | arr_price_full = np.zeros((n_samples, forward),dtype=np.float64) 46 | 47 | print("Loading...") 48 | for i in range(n_samples): 49 | arr_aug[i, :, :] = self.aug_data[i : i + n_timesteps,:] 50 | price_range = self.price_data[i + n_timesteps : i + n_timesteps + forward] 51 | #arr_price[i] = (price_range[-1]-price_range[0])/price_range[0] 52 | arr_price_full[i, :] = price_range 53 | #print(arr_aug[i]) 54 | #print(i) 55 | #print(n_samples) 56 | print("Ready.") 57 | 58 | self.arr_aug = arr_aug 59 | self.arr_price_full = arr_price_full 60 | 61 | #return arr_aug, arr_price_full 62 | 63 | 64 | def get_data_batch(self, batch_size): 65 | 66 | all_sentiment = self.arr_aug 67 | all_price = self.arr_price_full 68 | n_timesteps = all_price.shape[1] 69 | forward = all_price.shape[1] 70 | n_sentiments = all_sentiment.shape[2] 71 | n_pop = all_sentiment.shape[0] 72 | batch_sentiment = np.zeros((batch_size, n_timesteps, n_sentiments), dtype=np.float64) 73 | #batch_price = np.zeros(batch_size) 74 | batch_price = np.zeros((batch_size,forward), dtype=np.float64) 75 | batch_sequence = np.random.choice(n_pop, batch_size, replace=False) 76 | 77 | for i in range(len(batch_sequence)): 78 | batch_sentiment[i] = all_sentiment[batch_sequence[i]] 79 | batch_price[i] = all_price[batch_sequence[i]] 80 | 81 | return batch_sentiment, batch_price 82 | 83 | 84 | -------------------------------------------------------------------------------- /src/data_loader_helper.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | import pprint 3 | import msgpack 4 | import zlib 5 | import numpy as np 6 | 7 | import io_helper as ioh 8 | import datetime_helper as dh 9 | import load_augmento_data_helper as ladh 10 | #import load_binance_data_helper as lbdh 11 | import load_kraken_data_helper as lbdh 12 | 13 | 14 | def find_missing_date_batches(missing_days, required_days): 15 | missing_day_batches = [] 16 | for i_amd in range(len(missing_days)): 17 | if i_amd > 0 and (missing_days[i_amd] - missing_days[i_amd-1]).days == 1: 18 | missing_day_batches[-1].append(missing_days[i_amd]) 19 | else: 20 | missing_day_batches.append([missing_days[i_amd]]) 21 | return missing_day_batches 22 | 23 | def strip_data_by_time(t_data, data, t_min, t_max): 24 | data = np.array([s for s, t in zip(data, t_data) if t >= t_min and t <= t_max]) 25 | t_data = np.array([t for t in t_data if t >= t_min and t <= t_max]) 26 | return t_data, data 27 | 28 | def load_data(path_data="data/cache", 29 | augmento_coin=None, 30 | augmento_source=None, 31 | binance_symbol=None, 32 | dt_bin_size=None, 33 | datetime_start=None, 34 | datetime_end=None, 35 | augmento_api_key=None): 36 | 37 | datetime_end = min(datetime.datetime.now(), datetime_end) 38 | 39 | # check the input arguments 40 | if None in [binance_symbol, augmento_coin, augmento_source, dt_bin_size, datetime_start, datetime_end]: 41 | raise Exception("missing required param(s) in load_data()") 42 | 43 | # specify the path for the binance data cache 44 | path_augmento_data = "{:s}/augmento/{:s}/{:s}/{:d}".format(*(path_data, augmento_source, augmento_coin, dt_bin_size)) 45 | path_augmento_topics = "{:s}/augmento/".format(path_data) 46 | 47 | # specify the path for the augmento data cache 48 | #path_binance_data = "{:s}/binance/{:s}/{:d}".format(*(path_data, binance_symbol, dt_bin_size)) 49 | path_binance_data = "{:s}/kraken/{:s}/{:d}".format(*(path_data, binance_symbol, dt_bin_size)) 50 | 51 | # make sure all the paths exist 52 | ioh.check_path(path_augmento_data, create_if_not_exist=True) 53 | ioh.check_path(path_binance_data, create_if_not_exist=True) 54 | 55 | # check which days of data exist for the augmento data and binance data 56 | augmento_dates = dh.list_file_dates_for_path(path_augmento_data, ".msgpack.zlib", "%Y%m%d") 57 | binance_dates = dh.list_file_dates_for_path(path_binance_data, ".msgpack.zlib", "%Y%m%d") 58 | 59 | # remove any dates from the last 3 days, so we reload recent data 60 | datetime_now = datetime.datetime.now() 61 | augmento_dates = [el for el in augmento_dates if el < dh.add_days_to_datetime(datetime_now, -3)] 62 | binance_dates = [el for el in binance_dates if el < dh.add_days_to_datetime(datetime_now, -3)] 63 | 64 | # get a list of the days we need 65 | required_dates = dh.get_datetimes_between_datetimes(datetime_start, datetime_end) 66 | 67 | # get a list of the days we're missing for augmento and binance data 68 | augmento_missing_dates = sorted(list(set(required_dates) - set(augmento_dates))) 69 | binance_missing_dates = sorted(list(set(required_dates) - set(binance_dates))) 70 | 71 | # group the missing days by batch 72 | augmento_missing_batches = find_missing_date_batches(augmento_missing_dates, required_dates) 73 | binance_missing_batches = find_missing_date_batches(binance_missing_dates, required_dates) 74 | 75 | # load the augmento keys 76 | aug_keys = ladh.load_keys(path_augmento_topics) 77 | 78 | # load the binance keys 79 | bin_keys = lbdh.load_keys() 80 | 81 | # for each of the missing batches of augmento data, get the data and cache it 82 | for abds in augmento_missing_batches: 83 | 84 | # get the data for the batch and cache it 85 | ladh.load_and_cache_data(path_augmento_data, 86 | augmento_source, 87 | augmento_coin, 88 | dt_bin_size, 89 | abds[0], 90 | dh.add_days_to_datetime(abds[-1], 1)) 91 | 92 | # for each of the missing batches of binance data, get the data and cache it 93 | for bbds in binance_missing_batches: 94 | 95 | # get the data for the batch and cache it 96 | lbdh.load_and_cache_data(path_binance_data, 97 | binance_symbol, 98 | dt_bin_size, 99 | bbds[0], 100 | dh.add_days_to_datetime(bbds[-1], 1)) 101 | 102 | # load the data 103 | t_aug_data, aug_data = ladh.load_cached_data(path_augmento_data, datetime_start, datetime_end) 104 | t_bin_data, bin_data = lbdh.load_cached_data(path_binance_data, datetime_start, datetime_end) 105 | 106 | # strip the data 107 | t_min = max([t_aug_data[0], t_bin_data[0], dh.datetime_to_epoch(datetime_start)]) 108 | t_max = min([t_aug_data[-1], t_bin_data[-1], dh.datetime_to_epoch(datetime_end)]) 109 | t_aug_data, aug_data = strip_data_by_time(t_aug_data, aug_data, t_min, t_max) 110 | t_bin_data, bin_data = strip_data_by_time(t_bin_data, bin_data, t_min, t_max) 111 | 112 | return t_aug_data, t_bin_data, aug_data, bin_data, aug_keys, bin_keys 113 | 114 | 115 | 116 | 117 | -------------------------------------------------------------------------------- /src/load_augmento_data_helper.py: -------------------------------------------------------------------------------- 1 | import requests 2 | import time 3 | import pprint 4 | import zlib 5 | import msgpack 6 | import numpy as np 7 | 8 | import datetime_helper as dh 9 | 10 | # define the base url of the endpoint 11 | base_url = "http://api-dev.augmento.ai/v0.1" 12 | 13 | def load_keys(path_input): 14 | 15 | # if a list of topics doesn't exist, cache it 16 | path_augmento_topics = "{:s}/topics.msgpack.zlib".format(path_input) 17 | try: 18 | with open(path_augmento_topics, "rb") as f: 19 | augmento_topics = msgpack.unpackb(zlib.decompress(f.read()), encoding='utf-8') 20 | except: 21 | augmento_topics = requests.request("GET", "{:s}/topics".format(base_url), timeout=10).json() 22 | with open(path_augmento_topics, "wb") as f: 23 | f.write(zlib.compress(msgpack.packb(augmento_topics))) 24 | 25 | return {v : int(k) for k, v in augmento_topics.items()} 26 | 27 | 28 | def load_and_cache_data(path_output, source, coin, dt_bin_size, datetime_start, datetime_end): 29 | 30 | # make sure the start date and end date are rounded to the nearest day 31 | datetime_start = dh.round_datetime_to_day_start(datetime_start) 32 | datetime_end = dh.round_datetime_to_day_start(datetime_end) 33 | 34 | # make sure the source exists 35 | available_sources = requests.request("GET", "{:s}/sources".format(base_url), timeout=10).json() 36 | if source not in available_sources: 37 | raise Exception("invalid augmento source: {:s} not in: {:s}".format(*(source, available_sources))) 38 | 39 | # make sure the coin exists 40 | available_coins = requests.request("GET", "{:s}/coins".format(base_url), timeout=10).json() 41 | if coin not in available_coins: 42 | raise Exception("invalid augmento coin: {:s} not in: {:s}".format(*(coin, available_coins))) 43 | 44 | # make sure the bin_size exists 45 | available_bin_sizes = requests.request("GET", "{:s}/bin_sizes".format(base_url), timeout=10).json() 46 | available_bin_sizes = {v : k for k, v in available_bin_sizes.items()} 47 | if dt_bin_size not in available_bin_sizes: 48 | raise Exception("invalid augmento bin_size: {:s} not in: {:s}".format(*(dt_bin_size, available_bin_sizes))) 49 | 50 | # initialise a store for the data we're downloading 51 | sentiment_data = [] 52 | 53 | # define a start pointer to track multiple requests 54 | start_ptr = 0 55 | count_ptr = 1000 56 | 57 | # get the data 58 | while start_ptr >= 0: 59 | 60 | # define the parameters of the request 61 | params = { 62 | "source" : source, 63 | "coin" : coin, 64 | "bin_size" : available_bin_sizes[dt_bin_size], 65 | "count_ptr" : count_ptr, 66 | "start_ptr" : start_ptr, 67 | "start_datetime" : datetime_start.strftime("%Y-%m-%dT%H:%M:%SZ"), 68 | "end_datetime" : datetime_end.strftime("%Y-%m-%dT%H:%M:%SZ"), 69 | } 70 | 71 | # make the request 72 | r = requests.request("GET", "{:s}/events/aggregated".format(base_url), params=params, timeout=10) 73 | 74 | # if the request was ok, add the data and increment the start_ptr 75 | # else return an error 76 | if r.status_code == 200: 77 | temp_data = r.json() 78 | start_ptr += count_ptr 79 | else: 80 | raise Exception("api call failed with status_code {:d}".format(r.status_code)) 81 | 82 | # if we didn't get any data, assume we've got all the data 83 | if len(temp_data) == 0: 84 | start_ptr = -1 85 | 86 | # extend the data store 87 | sentiment_data.extend(temp_data) 88 | 89 | if len(temp_data) > 0: 90 | # print the progress 91 | str_print = "got augmento data from {:s} to {:s}".format(*(sentiment_data[0]["datetime"], 92 | sentiment_data[-1]["datetime"],)) 93 | print(str_print) 94 | 95 | # sleep 96 | time.sleep(2.0) 97 | 98 | # get datetimes for all datapoints 99 | datetimes = [dh.epoch_to_datetime(el["t_epoch"]) for el in sentiment_data] 100 | 101 | # get the starts of all the days 102 | days = sorted(list(set([dh.round_datetime_to_day_start(el) for el in datetimes]))) 103 | 104 | # for each of the start dates, cache the data for that day 105 | for day in days: 106 | 107 | # generate the output filename 108 | output_filename_short = dh.datetime_to_str(day, timestamp_format_str="%Y%m%d") 109 | output_filename = "{:s}/{:s}.msgpack.zlib".format(*(path_output, output_filename_short)) 110 | 111 | # generate/filter the output data 112 | temp_start = dh.datetime_to_epoch(day) 113 | temp_end = dh.datetime_to_epoch(dh.add_days_to_datetime(day, 1)) 114 | 115 | # get the data for this day (note that t_epoch is the OPEN time of the bin) 116 | output_data = [el for el in sentiment_data if el["t_epoch"] >= temp_start and el["t_epoch"] < temp_end] 117 | 118 | # save the data 119 | with open(output_filename, "wb") as f: 120 | f.write(zlib.compress(msgpack.packb(output_data))) 121 | 122 | def load_cached_data(path_input, datetime_start, datetime_end): 123 | 124 | # initialise the output data 125 | output_data = [] 126 | 127 | # get a list of the files we need to open 128 | required_dates = dh.get_datetimes_between_datetimes(datetime_start, datetime_end) 129 | 130 | # go through all the dates and load the corrisponding files 131 | for rd in required_dates: 132 | 133 | # load the file 134 | input_filename_short = dh.datetime_to_str(rd, timestamp_format_str="%Y%m%d") 135 | input_filename = "{:s}/{:s}.msgpack.zlib".format(*(path_input, input_filename_short)) 136 | try: 137 | with open(input_filename, "rb") as f: 138 | output_data.extend(msgpack.unpackb(zlib.decompress(f.read()), encoding='utf-8')) 139 | except: 140 | pass 141 | 142 | # format the data 143 | t_data = np.array([el["t_epoch"] for el in output_data], dtype=np.float64) 144 | feat_data = np.array([el["counts"] for el in output_data], dtype=np.float64) 145 | 146 | return t_data, feat_data 147 | 148 | -------------------------------------------------------------------------------- /augmento_client/rest_api.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # coding: utf-8 3 | # @Author: ArthurBernard 4 | # @Email: arthur.bernard.92@gmail.com 5 | # @Date: 2019-07-22 15:03:30 6 | # @Last modified by: ArthurBernard 7 | # @Last modified time: 2019-07-23 15:52:22 8 | 9 | """ Client connector to Augmento REST API. 10 | 11 | Examples 12 | -------- 13 | >>> ra = RequestAugmento(logging_level='DEBUG') 14 | >>> df = ra.get_dataframe(source='twitter', coin='bitcoin', bin_size='24H', start='2019-06-01T00:00:00Z', end='2019-06-02T00:00:00Z') 15 | >>> print(df.loc[:, 'Hacks':'Banks']) 16 | Hacks Pessimistic/Doubtful Banks 17 | date 18 | 2019-06-01T00:00:00Z 7 15 33 19 | 20 | """ 21 | 22 | # Built-in packages 23 | import logging 24 | import json 25 | import time 26 | import datetime 27 | 28 | # External packages 29 | import requests 30 | import pandas as pd 31 | 32 | # Local packages 33 | 34 | __all__ = ['RequestAugmento'] 35 | 36 | # TODO : add better doctests/examples 37 | 38 | 39 | class RequestAugmento: 40 | """ Class to request Augmento data from REST public API. 41 | 42 | Methods 43 | ------- 44 | send_request(method, **params) 45 | Return answere of request in list or dict. 46 | get_data(source, coin, bin_size, start, end, start_ptr=0, count_ptr=1000) 47 | Return aggregated event data in list of list. 48 | get_dataframe(source, coin, bin_size, start, end) 49 | Return aggregated event in a dataframe. 50 | get_database(source, coin, bin_size, start, end) 51 | Merge several requests of aggregated event in a dataframe. 52 | 53 | """ 54 | 55 | def __init__(self, url='http://api-dev.augmento.ai/v0.1/', 56 | logging_level='WARNING'): 57 | """ Initialize object. """ 58 | self.url = url 59 | self.logger = logging.getLogger('get_augmento_data.' + __name__) 60 | self.logger.setLevel(logging_level) 61 | self.logger.debug('Starting augmento client') 62 | 63 | def send_request(self, method, **params): 64 | """ Send a request to Augmento REST public API. 65 | 66 | Parameters 67 | ---------- 68 | method : str 69 | Name of the relevent request. 70 | **params : dict 71 | Relevent parameters, cf augemento documentation [1]_. 72 | 73 | Returns 74 | ------- 75 | dict 76 | Relevant data. 77 | 78 | References 79 | ---------- 80 | .. [1] http://api-dev.augmento.ai/v0.1/documentation#introduction 81 | 82 | """ 83 | self.logger.debug(f'{method} request with {params} parameters.') 84 | 85 | # Try and catch some exceptions 86 | try: 87 | ans = requests.get(self.url + method, params) 88 | 89 | return json.loads(ans.text) 90 | 91 | except json.decoder.JSONDecodeError: 92 | self.logger.error('JSON error.') 93 | time.sleep(1) 94 | 95 | return self.send_request(method, **params) 96 | 97 | except requests.exceptions.ConnectionError: 98 | self.logger.error('HTTP error.') 99 | time.sleep(1) 100 | 101 | return self.send_request(method, **params) 102 | 103 | except Exception as e: 104 | self.logger.error('Unknown error {}.'.format(type(e)), 105 | exc_info=True) 106 | time.sleep(1) 107 | 108 | return self.send_request(method, **params) 109 | 110 | def get_data(self, source, coin, bin_size, start, end, start_ptr=0, 111 | count_ptr=1000): 112 | """ Request data to Augmento REST public API. 113 | 114 | Parameters 115 | ---------- 116 | source : str, {'bitcointalk', 'reddit', 'twitter'} 117 | Source of data. 118 | coin : str 119 | Name of a crypto-currency, cf augemento documentation [1]_. 120 | bin_size : str, {'1H', '24H'} 121 | Time between two observations. 122 | start, end : str, int or datetime 123 | Starting date and ending date. If string must be ISO 8601 format 124 | such that ('%Y-%m-%dT%H:%M:%SZ'), or if integer must be UTC 125 | timestamp, else can be a datetime object. 126 | start_ptr : int, optional 127 | Default is 0. 128 | count_ptr : int, optional 129 | Number of observation. 130 | 131 | Returns 132 | ------- 133 | list of list 134 | Relevant data from `date_0` to `date_T` as 135 | `[[x_1, ..., date_0, ts_0], ..., [x_1, ..., date_T, ts_T]]`. 136 | 137 | References 138 | ---------- 139 | .. [1] http://api-dev.augmento.ai/v0.1/documentation#introduction 140 | 141 | """ 142 | start = intel_date(start) 143 | end = intel_date(end) 144 | 145 | # Request data 146 | data = self.send_request( 147 | 'events/aggregated', source=source, coin=coin, bin_size=bin_size, 148 | start_datetime=start.strftime('%Y-%m-%dT%H:%M:%SZ'), 149 | end_datetime=end.strftime('%Y-%m-%dT%H:%M:%SZ'), 150 | start_ptr=start_ptr, count_ptr=count_ptr 151 | ) 152 | 153 | return [[*x['counts'], x['datetime'], x['t_epoch']] for x in data] 154 | 155 | def get_dataframe(self, source, coin, bin_size, start, end): 156 | """ Request data to Augmento REST public API. 157 | 158 | Parameters 159 | ---------- 160 | source : str, {'bitcointalk', 'reddit', 'twitter'} 161 | Source of data. 162 | coin : str 163 | Name of a crypto-currency, cf augemento documentation [1]_. 164 | bin_size : str, {'1H', '24H'} 165 | Time between two observations. 166 | start, end : str, int or datetime 167 | Starting date and ending date. If string must be ISO 8601 format 168 | such that ('%Y-%m-%dT%H:%M:%SZ'), or if integer must be UTC 169 | timestamp, else can be a datetime object. 170 | Warning : `end` and `start` must have less than 1000 observations 171 | between. 172 | 173 | 174 | Returns 175 | ------- 176 | pd.DataFrame 177 | Relevant dataframe. 178 | 179 | References 180 | ---------- 181 | .. [1] http://api-dev.augmento.ai/v0.1/documentation#introduction 182 | 183 | """ 184 | # Request data 185 | data = self.get_data( 186 | source=source, coin=coin, bin_size=bin_size, start=start, end=end 187 | ) 188 | 189 | return self._set_dataframe(data) 190 | 191 | def get_database(self, source, coin, bin_size, start, end): 192 | """ Merge several data request to Augmento REST public API. 193 | 194 | Parameters 195 | ---------- 196 | source : str, {'bitcointalk', 'reddit', 'twitter'} 197 | Source of data. 198 | coin : str 199 | Name of a crypto-currency, cf augemento documentation [1]_. 200 | bin_size : str, {'1H', '24H'} 201 | Time between two observations. 202 | start, end : str, int or datetime 203 | Starting date and ending date. If string must be ISO 8601 format 204 | such that ('%Y-%m-%dT%H:%M:%SZ'), or if integer must be UTC 205 | timestamp, else can be a datetime object. 206 | 207 | Returns 208 | ------- 209 | pd.DataFrame 210 | Relevant dataframe. 211 | 212 | References 213 | ---------- 214 | .. [1] http://api-dev.augmento.ai/v0.1/documentation#introduction 215 | 216 | """ 217 | if bin_size == '24H': 218 | nb_obs_per_day = 1 219 | elif bin_size == '1H': 220 | nb_obs_per_day = 24 221 | else: 222 | raise ValueError('Unknown bin size') 223 | 224 | start = intel_date(start) 225 | end = intel_date(end) 226 | 227 | dt = (end - start).days * nb_obs_per_day 228 | 229 | data = [] 230 | 231 | # Iterative download 232 | for i in range(0, dt, 1000): 233 | # Request data 234 | data += self.get_data( 235 | source, coin, bin_size, start=start, end=end, start_ptr=i, 236 | ) 237 | pct = i / ((dt - 1) // 1000 * 1000) 238 | print('Downloaded {:7.2%} [{}{}] '.format( 239 | pct, '=' * int(49 * pct), 240 | '>' * (1 - int(pct)) + ' ' * int(49 * (1 - pct)) 241 | ), end='\r') 242 | 243 | # Sleep 244 | time.sleep(.1) 245 | 246 | return self._set_dataframe(data) 247 | 248 | def _set_dataframe(self, data): 249 | # Request topic names 250 | topics = self.send_request('topics') 251 | 252 | # Set dataframe 253 | df = pd.DataFrame(data) 254 | df = df.rename(columns={ 255 | **{93: 'date', 94: 'TS'}, 256 | **{int(k): a for k, a in topics.items()} 257 | }) 258 | 259 | return df.set_index('date') 260 | 261 | 262 | def intel_date(date, form='%Y-%m-%dT%H:%M:%SZ'): 263 | """ Convert date to timedate object. """ 264 | if isinstance(date, datetime.datetime): 265 | return date 266 | 267 | elif isinstance(date, str): 268 | return datetime.datetime.strptime(date, form) 269 | 270 | elif isinstance(date, int): 271 | return datetime.datetime.utcfromtimestamp(date) 272 | 273 | else: 274 | raise ValueError('Unknown date object, must be datetime, string\ 275 | (with relevent format), or int (UTC timestamp)') 276 | 277 | 278 | if __name__ == '__main__': 279 | 280 | import doctest 281 | import yaml 282 | import logging.config 283 | 284 | # Load config logging 285 | with open('./augmento_client/logging.ini', 'rb') as f: 286 | config = yaml.safe_load(f.read()) 287 | 288 | logging.config.dictConfig(config) 289 | 290 | # Run tests 291 | doctest.testmod() 292 | -------------------------------------------------------------------------------- /src/analysis_helper.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import numba as nb 3 | 4 | 5 | @nb.jit("(f8[:])(f8[:], f8[:])", nopython=True, nogil=True, cache=True) 6 | def nb_safe_divide(a, b): 7 | # divide each element in a by each element in b 8 | # if element b == 0.0, return element = 0.0 9 | c = np.zeros(a.shape[0], dtype=np.float64) 10 | for i in range(a.shape[0]): 11 | if b[i] != 0.0: 12 | c[i] = a[i] / b[i] 13 | return c 14 | 15 | @nb.jit("(f8[:])(f8[:], i8)", nopython=True, nogil=True, parallel=False) 16 | def nb_causal_rolling_average(arr, window_size): 17 | 18 | # create an output array 19 | out_arr = np.zeros(arr.shape[0]) 20 | 21 | # create an array from the input array, with added space for the rolling window 22 | new_arr = np.hstack((np.ones(window_size-1) * arr[0], arr)) 23 | 24 | # for each output element, find the mean of the last few input elements 25 | #for i in nb.prange(out_arr.shape[0]): 26 | for i in range(out_arr.shape[0]): 27 | out_arr[i] = np.mean(new_arr[i : i + window_size]) 28 | 29 | return out_arr 30 | 31 | @nb.jit("(f8[:])(f8[:], i8)", nopython=True, nogil=True, parallel=False) 32 | def nb_causal_rolling_sd(arr, window_size): 33 | 34 | # create an output array 35 | out_arr = np.zeros(arr.shape[0]) 36 | 37 | # create an array from the input array, with added space for the rolling window 38 | new_arr = np.hstack((np.ones(window_size-1) * arr[0], arr)) 39 | 40 | # for each output element, find the mean and std of the last few 41 | # input elements, and standardise the input element by the mean and std of the window 42 | #for i in nb.prange(out_arr.shape[0]): 43 | for i in range(out_arr.shape[0]): 44 | num = new_arr[i+window_size-1] - np.mean(new_arr[i : i + window_size-1]) 45 | denom = np.std(new_arr[i : i + window_size-1]) 46 | if denom != 0.0: 47 | out_arr[i] = num / denom 48 | 49 | return out_arr 50 | 51 | @nb.jit("(f8[:])(f8[:], i8)", nopython=True, nogil=True, parallel=False) 52 | def nb_causal_rolling_sd_rand(arr, window_size_rand): 53 | 54 | # create an output array 55 | out_arr = np.zeros(arr.shape[0]) 56 | 57 | # create an array from the input array, with added space for the rolling window 58 | new_arr = np.hstack((np.ones(window_size_rand-1) * arr[0], arr)) 59 | 60 | # create an array from the input array, with added space for the rolling window 61 | new_arr = np.hstack((np.ones(window_size_rand-1) * arr[0], arr)) 62 | # for each output element, find the mean and std of the last few 63 | # input elements, and standardise the input element by the mean and std of the window 64 | #for i in nb.prange(out_arr.shape[0]): 65 | for i in range(out_arr.shape[0]): 66 | window_size_std = 1.0 67 | window_size = round(np.random.normal(window_size_rand, window_size_std)) 68 | num = new_arr[i+window_size-1] - np.mean(new_arr[i : i + window_size-1]) 69 | denom = np.std(new_arr[i : i + window_size-1]) 70 | if denom != 0.0: 71 | out_arr[i] = num / denom 72 | 73 | return out_arr 74 | 75 | @nb.jit("(f8[:])(f8[:], i8)", nopython=True, nogil=True, parallel=False) 76 | def nb_causal_rolling_norm(arr, window_size): 77 | 78 | # create an output array 79 | out_arr = np.zeros(arr.shape[0]) 80 | 81 | # create an array from the input array, with added space for the rolling window 82 | new_arr = np.hstack((np.ones(window_size-1) * arr[0], arr)) 83 | 84 | # for each output element, find the mean and std of the last few 85 | # input elements, and standardise the input element by the mean and std of the window 86 | #for i in nb.prange(out_arr.shape[0]): 87 | for i in range(out_arr.shape[0]): 88 | num = new_arr[i+window_size-1] - np.mean(new_arr[i : i + window_size]) 89 | denom = np.max(np.abs(new_arr[i : i + window_size] - np.mean(new_arr[i : i + window_size]))) 90 | if denom != 0.0: 91 | out_arr[i] = num / denom 92 | 93 | return out_arr 94 | 95 | @nb.jit("(f8[:])(f8[:], i8, f8)", nopython=True, nogil=True, parallel=False) 96 | def nb_causal_rolling_norm_rand(arr, window_size_rand, peturb): 97 | 98 | # create an output array 99 | out_arr = np.zeros(arr.shape[0]) 100 | 101 | # create an array from the input array, with added space for the rolling window 102 | new_arr = np.hstack((np.ones(window_size_rand-1) * arr[0], arr)) 103 | 104 | index_new = window_size_rand 105 | 106 | # for each output element, find the mean and std of the last few 107 | # input elements, and standardise the input element by the mean and std of the window 108 | #for i in nb.prange(out_arr.shape[0]): 109 | for i in range(out_arr.shape[0]): 110 | 111 | window_size_std = peturb * np.float64(window_size_rand) 112 | window_size = round(np.random.normal(window_size_rand, window_size_std)) 113 | 114 | i_end_new = i + window_size_rand 115 | i_start_new = i_end_new - window_size 116 | 117 | if i_start_new < 0: 118 | i_start_new = 0 119 | 120 | out_arr[i] = np.mean(new_arr[i_start_new : i_end_new]) 121 | #print(out_arr[i-1:i+1]) 122 | 123 | #num = new_arr[i+window_size-1] - np.mean(new_arr[i : i + window_size]) 124 | #denom = np.max(np.abs(new_arr[i : i + window_size] - np.mean(new_arr[i : i + window_size]))) 125 | #if denom != 0.0: 126 | # out_arr[i] = num / denom 127 | 128 | return out_arr 129 | 130 | @nb.jit("(f8[:])(f8[:], i8)", nopython=True, nogil=True, parallel=False) 131 | def nb_causal_rolling_average(arr, window_size): 132 | 133 | # create an output array 134 | out_arr = np.zeros(arr.shape[0]) 135 | 136 | # create an array from the input array, with added space for the rolling window 137 | new_arr = np.hstack((np.ones(window_size-1) * arr[0], arr)) 138 | 139 | # for each output element, find the mean of the last few input elements 140 | #for i in nb.prange(out_arr.shape[0]): 141 | for i in range(out_arr.shape[0]): 142 | out_arr[i] = np.mean(new_arr[i : i + window_size]) 143 | 144 | return out_arr 145 | 146 | 147 | 148 | #@nb.jit("(f8[:])(f8[:], f8[:], i8, i8, f8)", nopython=True, nogil=True) 149 | def nb_calc_sentiment_score_rand_b(sent_a, sent_b, ra_win_size_short, ra_win_size_long,peturb): 150 | # example method for creating a stationary sentiment score based on Augmento data 151 | 152 | # compare the raw sentiment values 153 | sent_ratio = nb_safe_divide(sent_a, sent_b) 154 | 155 | # smooth the sentiment ratio 156 | sent_ratio_short = nb_causal_rolling_norm_rand(sent_ratio, ra_win_size_short, peturb) 157 | sent_ratio_long = nb_causal_rolling_norm_rand(sent_ratio, ra_win_size_long, peturb) 158 | 159 | # create a stationary(ish) representation of the smoothed sentiment ratio 160 | sent_score = sent_ratio_short - sent_ratio_long 161 | 162 | return sent_score 163 | 164 | 165 | @nb.jit("(f8[:])(f8[:], f8[:], i8, i8, f8)", nopython=True, nogil=True) 166 | def nb_calc_sentiment_score_rand_a(sent_a, sent_b, ra_win_size, std_win_size, peturb): 167 | # example method for creating a stationary sentiment score based on Augmento data 168 | 169 | # compare the raw sentiment values 170 | sent_ratio = nb_safe_divide(sent_a, sent_b) 171 | 172 | # smooth the sentiment ratio 173 | sent_ratio_smooth = nb_causal_rolling_norm_rand(sent_ratio, ra_win_size, peturb) 174 | 175 | # create a stationary(ish) representation of the smoothed sentiment ratio 176 | sent_score = nb_causal_rolling_sd(sent_ratio_smooth, std_win_size) 177 | 178 | return sent_score 179 | 180 | @nb.jit("(f8[:])(f8[:], f8[:], i8, i8)", nopython=True, nogil=True) 181 | def nb_calc_sentiment_score_a(sent_a, sent_b, ra_win_size, std_win_size): 182 | # example method for creating a stationary sentiment score based on Augmento data 183 | 184 | # compare the raw sentiment values 185 | sent_ratio = nb_safe_divide(sent_a, sent_b) 186 | 187 | # smooth the sentiment ratio 188 | sent_ratio_smooth = nb_causal_rolling_average(sent_ratio, ra_win_size) 189 | 190 | # create a stationary(ish) representation of the smoothed sentiment ratio 191 | sent_score = nb_causal_rolling_sd(sent_ratio_smooth, std_win_size) 192 | 193 | return sent_score 194 | 195 | @nb.jit("(f8[:])(f8[:], f8[:], i8, i8)", nopython=True, nogil=True) 196 | def nb_calc_sentiment_score_b(sent_a, sent_b, ra_win_size_short, ra_win_size_long): 197 | # example method for creating a stationary sentiment score based on Augmento data 198 | 199 | # compare the raw sentiment values 200 | sent_ratio = nb_safe_divide(sent_a, sent_b) 201 | 202 | # smooth the sentiment ratio 203 | sent_ratio_short = nb_causal_rolling_average(sent_ratio, ra_win_size_short) 204 | sent_ratio_long = nb_causal_rolling_average(sent_ratio, ra_win_size_long) 205 | 206 | # create a stationary(ish) representation of the smoothed sentiment ratio 207 | sent_score = sent_ratio_short - sent_ratio_long 208 | 209 | return sent_score 210 | 211 | @nb.jit("(f8[:])(f8[:], f8[:], i8, i8)", nopython=True, nogil=True) 212 | def nb_calc_sentiment_score_c(sent_a, sent_b, ra_win_size, std_win_size): 213 | # example method for creating a stationary sentiment score based on Augmento data 214 | 215 | # compare the raw sentiment values 216 | sent_ratio = nb_safe_divide(sent_a, sent_b) 217 | 218 | # smooth the sentiment ratio 219 | sent_ratio_smooth = nb_causal_rolling_average(sent_ratio, ra_win_size) 220 | 221 | # create a stationary(ish) representation of the smoothed sentiment ratio 222 | sent_score = nb_causal_rolling_norm(sent_ratio_smooth, std_win_size) 223 | 224 | return sent_score 225 | 226 | @nb.jit("(f8[:])(f8[:], f8[:], f8, f8)", nopython=True, nogil=True, cache=True) 227 | def nb_backtest_a(price, sent_score, start_pnl, buy_sell_fee): 228 | # example backtest with approximate model for long/short contracts 229 | 230 | # create an array to hold our pnl, and set the first value 231 | pnl = np.zeros(price.shape, dtype=np.float64) 232 | pnl[0] = start_pnl 233 | 234 | # for each step, run the market model 235 | for i_p in range(1, price.shape[0]): 236 | 237 | # if sentiment score is positive, simulate long position 238 | # else if sentiment score is negative, simulate short position 239 | # else if the sentiment score is 0.0, hold 240 | # (note that this is a very approximate market simulation!) 241 | n_sample_delay = 2 242 | if i_p < n_sample_delay: 243 | pnl[i_p] = pnl[i_p-1] 244 | if sent_score[i_p-n_sample_delay] > 0.0: 245 | pnl[i_p] = (price[i_p] / price[i_p-1]) * pnl[i_p-1] 246 | elif sent_score[i_p-n_sample_delay] <= 0.0: 247 | pnl[i_p] = (price[i_p-1] / price[i_p]) * pnl[i_p-1] 248 | elif sent_score[i_p-n_sample_delay] == 0.0: 249 | pnl[i_p] = pnl[i_p-1] 250 | 251 | # simulate a trade fee if we cross from long to short, or visa versa 252 | if i_p > 1 and np.sign(sent_score[i_p-1]) != np.sign(sent_score[i_p-2]): 253 | pnl[i_p] = pnl[i_p] - (buy_sell_fee * pnl[i_p]) 254 | 255 | return pnl 256 | 257 | 258 | 259 | 260 | @nb.jit("(f8[:])(f8[:], i8)", nopython=True, nogil=True, cache=True) 261 | def moving_average(arr, window): 262 | 263 | # output array 264 | ma_arr = np.zeros(arr.shape[0]) 265 | 266 | # add space for rolling window 267 | new_arr = np.hstack((np.ones(window-1) * arr[0], arr)) 268 | 269 | # calculate moving average 270 | #for i in nb.prange(arr.shape[0]): 271 | for i in range(arr.shape[0]): 272 | num = new_arr[i+window-1] - np.mean(new_arr[i : i+window-1]) 273 | denom = np.std(new_arr[i : i + window-1]) 274 | if denom != 0.0: 275 | ma_arr[i] = num / denom 276 | 277 | return ma_arr 278 | 279 | #@nb.jit("(f8[:])(f8[:], i8)", nopython=True, nogil=True, cache=True) 280 | #def signal_ma(positive, negative, short, long): 281 | 282 | 283 | 284 | 285 | 286 | @nb.jit("(f8[:])(f8[:], f8[:], f8[:], f8, f8, f8)",nopython=True, nogil=True,cache=True) 287 | def sma_crossover_backtest(price, leading_arr, lagging_arr, start_pnl, buy_sell_fee, threshold=0.0): 288 | 289 | # create an array to hold our pnl, and set the first value 290 | pnl = np.zeros(price.shape, dtype=np.float64) 291 | pnl[0] = start_pnl 292 | 293 | # BUY if Leading SMA is above Lagging SMA by some threshold. 294 | # SELL if Leading SMA is below Lagging SMA by some threshold. 295 | sent_signal = leading_arr - lagging_arr 296 | 297 | # for each step, run the market model 298 | for i_p in range(1, price.shape[0]): 299 | if sent_signal[i_p-1] > threshold: 300 | pnl[i_p] = (price[i_p] / price[i_p-1]) * pnl[i_p-1] 301 | elif sent_signal[i_p-1] < threshold: 302 | pnl[i_p] = (price[i_p-1] / price[i_p]) * pnl[i_p-1] 303 | elif sent_signal[i_p-1] == threshold: 304 | pnl[i_p] = pnl[i_p-1] 305 | 306 | # simulate a trade fee if we cross from long to short, or visa versa 307 | if i_p > 1 and np.sign(sent_signal[i_p-1]) != np.sign(sent_signal[i_p-2]): 308 | pnl[i_p] = pnl[i_p] - (buy_sell_fee * pnl[i_p]) 309 | 310 | return pnl 311 | 312 | 313 | #@nb.jit("(f8[:])(f8[:], f8[:], i8)", nopython=True, nogil=True, cache=True) 314 | #def forward_volume(volume_data, price_data, threshold=2000000): 315 | 316 | # price_rate_change = np.full(len(volume_data), np.nan) 317 | 318 | # for i in range(len(volume_data)): 319 | # sum_volume = 0 320 | 321 | # for j in range(len(price_data)): 322 | # sum_volume += price_data[j] 323 | 324 | # if sum_volume >= threshold: 325 | # price_rate_change[i] = (price_data[j] - price_data[i])/price_data[i] 326 | # break 327 | 328 | @nb.jit("(f8[:])(f8[:], f8[:], i8)", nopython=True, nogil=True, cache=True) 329 | def forward_volume(volume_data, price_data, threshold=2000000): 330 | 331 | price_rate_change = np.zeros(len(price_data)) 332 | 333 | for i in range((len(volume_data))): 334 | j = i+1 335 | sum_volume = 0.0 336 | 337 | while (sum_volume < threshold) & (j < len(price_rate_change)): 338 | sum_volume += volume_data[j] 339 | 340 | if sum_volume >= threshold: 341 | price_rate_change[i] = (price_data[j]-price_data[i])/price_data[i] 342 | 343 | j += 1 344 | 345 | return price_rate_change 346 | 347 | @nb.jit("(f8[:])(f8[:], f8[:], f8)", nopython=True, nogil=True, cache=True) 348 | def forward_volume(volume_data, price_data, threshold): 349 | 350 | price_rate_change = np.zeros(len(price_data)) 351 | 352 | for i in range((len(volume_data))): 353 | j = i+1 354 | sum_volume = 0.0 355 | 356 | while (sum_volume < threshold) & (j < len(price_rate_change)): 357 | sum_volume += volume_data[j] 358 | 359 | if sum_volume >= threshold: 360 | price_rate_change[i] = (price_data[j]-price_data[i])/price_data[i] 361 | 362 | j += 1 363 | 364 | return price_rate_change 365 | 366 | 367 | @nb.jit("(f8[:])(f8[:], i8)", nopython=True, nogil=True, cache=True) 368 | def volume_normalized(volume_data, n_hours): 369 | norm_volume = np.zeros(len(volume_data)) 370 | start = 0 371 | for i in range(n_hours,len(volume_data), n_hours): 372 | for j in range(start,i): 373 | norm_volume[j] = volume_data[j]/np.sum(volume_data[start:i]) 374 | start = i 375 | return norm_volume 376 | 377 | 378 | 379 | 380 | 381 | 382 | -------------------------------------------------------------------------------- /notebooks/2_moving_windows.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 2, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "import sys\n", 10 | "sys.path.insert(0, \"../src\")\n", 11 | "import example_helper as eh\n", 12 | "import analysis_helper as ah\n", 13 | "import msgpack\n", 14 | "import zlib\n", 15 | "import numpy as np\n", 16 | "import datetime\n", 17 | "import time\n", 18 | "import matplotlib.pyplot as plt\n", 19 | "import matplotlib.dates as md\n", 20 | "from matplotlib.pyplot import figure\n", 21 | "import pandas as pd\n", 22 | "import seaborn as sns; sns.set()" 23 | ] 24 | }, 25 | { 26 | "cell_type": "markdown", 27 | "metadata": {}, 28 | "source": [ 29 | "# Get Data" 30 | ] 31 | }, 32 | { 33 | "cell_type": "code", 34 | "execution_count": 3, 35 | "metadata": {}, 36 | "outputs": [], 37 | "source": [ 38 | "# define the location of the input file\n", 39 | "filename_augmento_topics = \"../data/example_data/augmento_topics.msgpack.zlib\"\n", 40 | "filename_augmento_data = \"../data/example_data/augmento_data.msgpack.zlib\"\n", 41 | "filename_bitmex_data = \"../data/example_data/bitmex_data.msgpack.zlib\"\n", 42 | "\n", 43 | "# load the example data\n", 44 | "all_data = eh.load_example_data(filename_augmento_topics,\n", 45 | " filename_augmento_data,\n", 46 | " filename_bitmex_data)\n", 47 | "aug_topics, aug_topics_inv, t_aug_data, aug_data, t_price_data, price_data = all_data\n", 48 | "all_topics = aug_data.T.astype(float)" 49 | ] 50 | }, 51 | { 52 | "cell_type": "markdown", 53 | "metadata": {}, 54 | "source": [ 55 | "# Example for Topics \"Bullish\" and \"Bearish\"" 56 | ] 57 | }, 58 | { 59 | "cell_type": "code", 60 | "execution_count": 4, 61 | "metadata": {}, 62 | "outputs": [], 63 | "source": [ 64 | "aug_signal_a = aug_data[:, aug_topics_inv[\"Bullish\"]].astype(np.float64)\n", 65 | "aug_signal_b = aug_data[:, aug_topics_inv[\"Bearish\"]].astype(np.float64)\n" 66 | ] 67 | }, 68 | { 69 | "cell_type": "code", 70 | "execution_count": 5, 71 | "metadata": {}, 72 | "outputs": [], 73 | "source": [ 74 | "# define the window size for the sentiment score calculation\n", 75 | "n_days = 7\n", 76 | "window_size = 24 * n_days\n", 77 | "\n", 78 | "# generate the sentiment score\n", 79 | "sent_score = ah.nb_calc_sentiment_score_a(aug_signal_a, aug_signal_b, window_size, window_size)\n", 80 | "\n", 81 | "# define some parameters for the backtest\n", 82 | "start_pnl = 1.0\n", 83 | "buy_sell_fee = 0.0075\n", 84 | "\n", 85 | "# run the backtest\n", 86 | "pnl = ah.nb_backtest_a(price_data, sent_score, start_pnl, buy_sell_fee)" 87 | ] 88 | }, 89 | { 90 | "cell_type": "markdown", 91 | "metadata": {}, 92 | "source": [ 93 | "# Compare various windows sizes" 94 | ] 95 | }, 96 | { 97 | "cell_type": "code", 98 | "execution_count": 6, 99 | "metadata": {}, 100 | "outputs": [], 101 | "source": [ 102 | "sent_score = ah.nb_calc_sentiment_score_a(aug_signal_a,aug_signal_b,1,2)\n", 103 | "pnl = ah.nb_backtest_a(price_data, sent_score, 1.0, 0.0075)" 104 | ] 105 | }, 106 | { 107 | "cell_type": "code", 108 | "execution_count": 7, 109 | "metadata": {}, 110 | "outputs": [], 111 | "source": [ 112 | "sent_score = ah.nb_calc_sentiment_score_a(aug_signal_a,aug_signal_b,7*24,7*24)\n", 113 | "pnl = ah.nb_backtest_a(price_data, sent_score, 1.0, 0.0075)" 114 | ] 115 | }, 116 | { 117 | "cell_type": "code", 118 | "execution_count": 8, 119 | "metadata": {}, 120 | "outputs": [], 121 | "source": [ 122 | "# different windows sizes for sentiment score b\n", 123 | "#h = 24\n", 124 | "s_days = 20 # short\n", 125 | "l_days = 20 # long\n", 126 | "\n", 127 | "win_all_a = np.zeros(shape=(s_days,l_days))\n", 128 | "win_all_b = np.zeros(shape=(s_days,l_days))\n", 129 | "\n", 130 | "# matrix of size (s_days,l_days)\n", 131 | "\n", 132 | "for i in range(0, s_days):\n", 133 | " for j in range(0, l_days):\n", 134 | " sent_score_a = ah.nb_calc_sentiment_score_a(aug_signal_a,aug_signal_b,(i+1)*24,(j+1)*24)\n", 135 | " sent_score_b = ah.nb_calc_sentiment_score_b(aug_signal_a, aug_signal_b, (i+1)*24,(j+1)*24)\n", 136 | " #pnl_a = ah.nb_backtest_a(price_data, sent_score_a, 1.0, 0.0075)\n", 137 | " #pnl_b = ah.nb_backtest_a(price_data, sent_score_b, 1.0, 0.0075)\n", 138 | " win_all_a[i,j] = ah.nb_backtest_a(price_data, sent_score_a, 1.0, 0.0075)[-1]\n", 139 | " win_all_b[i,j] = ah.nb_backtest_a(price_data, sent_score_b, 1.0, 0.0075)[-1]" 140 | ] 141 | }, 142 | { 143 | "cell_type": "code", 144 | "execution_count": 9, 145 | "metadata": {}, 146 | "outputs": [], 147 | "source": [ 148 | "##plot\n", 149 | "#cmap = sns.cubehelix_palette(50, hue=0.05, rot=0, light=0.0, dark=1.2, as_cmap=True)\n", 150 | "#figure(num=None, figsize=(10, 7), dpi=80, facecolor='w', edgecolor='k')\n", 151 | "#ax = sns.heatmap(win_all_a, linewidth=0.01, cmap=cmap)\n", 152 | "#plt.show()" 153 | ] 154 | }, 155 | { 156 | "cell_type": "code", 157 | "execution_count": 10, 158 | "metadata": {}, 159 | "outputs": [], 160 | "source": [ 161 | "##plot\n", 162 | "#cmap = sns.cubehelix_palette(50, hue=0.05, rot=0, light=0.0, dark=1.2, as_cmap=True)\n", 163 | "#figure(num=None, figsize=(10, 7), dpi=80, facecolor='w', edgecolor='k')\n", 164 | "#ax = sns.heatmap(win_all_b, linewidth=0.01, cmap=cmap)\n", 165 | "#plt.show()" 166 | ] 167 | }, 168 | { 169 | "cell_type": "code", 170 | "execution_count": 11, 171 | "metadata": {}, 172 | "outputs": [], 173 | "source": [ 174 | "# different windows sizes for sentiment score b\n", 175 | "#h = 24\n", 176 | "s_days = 20 # short\n", 177 | "l_days = 20 # long\n", 178 | "\n", 179 | "win_all_a = np.zeros(shape=(s_days,l_days))\n", 180 | "\n", 181 | "# matrix of size (s_days,l_days)\n", 182 | "\n", 183 | "for i in range(0, s_days):\n", 184 | " for j in range(0, l_days):\n", 185 | " sent_score_a = ah.nb_calc_sentiment_score_a(aug_signal_a,aug_signal_b,(i+1)*24,(j+1)*24)\n", 186 | " #pnl_a = ah.nb_backtest_a(price_data, sent_score_a, 1.0, 0.0075)\n", 187 | " #pnl_b = ah.nb_backtest_a(price_data, sent_score_b, 1.0, 0.0075)\n", 188 | " win_all_a[i,j] = ah.nb_backtest_a(price_data, sent_score_a, 1.0, 0.0075)[-1]\n" 189 | ] 190 | }, 191 | { 192 | "cell_type": "code", 193 | "execution_count": 12, 194 | "metadata": {}, 195 | "outputs": [ 196 | { 197 | "data": { 198 | "image/png": "iVBORw0KGgoAAAANSUhEUgAACNEAAAJBCAYAAABiALHAAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4xLjAsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy+17YcXAAAgAElEQVR4nOzde7SkVX0n/O/phsVtySUREBDkor1BBEQQkKgQg3eiwVejY2YcTRBfNck4EzMzy1zU15VkJmuMTJKlb7ybGKPxwki8ICAB0ebWgIIIGwLdiICASoOhgUCf8/5xTuft4KHPw35OVXVVfT5r9VqnnlO/2r9z6frWfmqf/czMzc0FAAAAAAAAAACm2YpRNwAAAAAAAAAAAKNmEQ0AAAAAAAAAAFPPIhoAAAAAAAAAAKaeRTQAAAAAAAAAAEw9i2gAAAAAAAAAAJh6FtEAAAAAAAAAADD1thnmYDMzM3OttXNzc5mZmRmr2mkde1z7Xo6xV6xoW5c2Ozs7lt+zUX+/Rzl2kvbBF3nIZXyspSxn3wzW3Lj+/xjHsce171GOPc1998n71tpN9WP6PVvu7JGbLGbqcnNc+x7l2OPa9yjHHnXf0zbHXqgf17lmIjfHyUhyc9TPKeM49qj7ntL5S1auXNlUu3HjxrGdq47r/484R8sQjON7m6Mce1z7HuXY49x339cK05hd3ttsMvTctBMNAAAAAAAAAABTzyIaAAAAAAAAAACmnkU0AAAAAAAAAABMPYtoAAAAAAAAAACYetuMugEAtl6llJ2TrE5ycq11XSnlo0mek+S+hbu8u9Z6xsgaBAAAAAAAAFgmFtEAsKhSyrFJPpRk1WaHn5nkubXW20fTFQAAAAAAAMBguJwTAI/mjUnemuS2JCml7JRkvyQfKqVcVUp5dylFjgAAAAAAAAATwU40AFOklLJrkl0X+dT6Wuv6zQ/UWk9dqNl0aM8k5yV5U5J/TvKlJL+R+d1qAAAAAAAAAMaaRTQA0+VtSd65yPF3J3nXlgprrTclOWXT7VLKXyR5XSyiAQAAAAAAACaARTQA0+X0JB9f5Pj6RY79G6WUw5KsqrV+fuHQTJKHlq81AAAAAAAAgNFZchFNKeXgJK9M8sQks0luS3JWrXXNgHsDYJktXLJpyQUzj2ImyemllPMyfzmn05J8Yrl6mwQyEwC6k5sA0J3cBIDu5CYAfazY0idLKW9J8umFm5cluXzh4w+VUn5nkI0BsHWptV6V5E+SfCvJ95J8u9b6d6PtaushMwGgO7kJAN3JTQDoTm4C0NdSO9G8LcnTa60bNj9YSvmzJFckee+gGgNg61Br3X+zj9+f5P2j62arJjMBoDu5CQDdyU0A6E5uAtDLFneiSfJQkm0XOb7DwucAgHkyEwC6k5sA0J3cBIDu5CYAvSy1E80fJbmylPL1JLcvHNsryfOS/N4gGwOAMSMzAaA7uQkA3clNAOhObgLQy8zc3NwW71BK2TvJSUn2TjKT5NYk59Zab3vMg83MbHmwLZibm8vMzMxY1U7r2OPa93KMvWLFUps7LW52dnYsv2ej/n6PcuzMPx8ul+bnxgbL2TePsJyZmWRuXP9/jOPY49r3KMee5r775H1r7ab6Mf2eLXf2yM0JITdH/n9z6sYe175HOfao+562OfZC/bjONRO5OVCTkJujfk4Zx7FH3feUzl+ycuXKptqNGzeO7Vx1XP9/xDlaHsW0v7c5yrHHte9Rjj3Offd9rTCN2eW9zSZDz80lF9Es62BjGDSj/mUex7HHte/lGNuT/fSMHUHD4E3dm4GjHHtc+x7l2NPct0U0j7neIhqGYepyc1z7HuXY49r3KMcedd/TNsdeqB/XuWYiN8eJRTRjMvao+57S+YtFNA1jW0TzmMnMMTKO722Ocuxx7XuUY49z3xbRDK92OcaO3Oys/TcbAAAAAAAAAAAmhEU0AAAAAAAAAABMPYtoAAAAAAAAAACYehbRAAAAAAAAAAAw9bYZdQMAAAAAwPQopeycZHWSk2ut60opH03ynCT3Ldzl3bXWM0bWIAAAAFPLIhoAAAAAYChKKccm+VCSVZsdfmaS59Zabx9NVwAAADDPIhoAAAAAoJdSyq5Jdl3kU+trres3u/3GJG9N8jcLdTsl2S/Jh0op+yU5I/M70cwOuGUAAAD4GStG3QAAAAAAMPbelmTtIv/etvmdaq2n1lov3OzQnknOS/LrSY7L/GWdfmMYDQMAAMAjzczNzQ1zvKEOBjBAM8v4WMN8blzOvhksmQlMiuXOHrnJYuQmMCnGda6ZUspu6bYTzab7r0tyYq113SOOn5LkdbXWUwbQJvPkJjApxjU3zTXHi9wEJoXc7Giol3OamWn/+ubm5prr5+bmsmJF26Y7s7Oz2Wab9m/Tww8/3GvslStXNo+9cePG5vqNGzc2f90PP/xwtttuu6baJHnwwQez7bbbNtU+9NBD2WmnnZrHvu+++7LLLoud71naPfesz+Met3NT7U9/em923HHHptok2bBhQ/PXfd999/Wq3X777Ztqk+SBBx7o9bPuO3br7+mDDz7YPC48Fn1yr2/m9smu1tq+9aOq3VQ/ytzs8zze57VCa2Ym87m58867NNXee+89vb7mvpnbJ+9H+RpplH3DMIwyN0c1Vx1l5vadq/bJzdZ5wAMPPNC77z5ziL65Oao5X98MGMU8ecOGDc2ZmcznZp+fdd/fs3G1sFDmZxbLLKWUcliSVbXWzy8cmkny0HL2xs8aRW72yb2k/7xrWueqfeZ8fTOgz89rFHOfpH/+jPI8a5++d9hhh+ax77///l4/6912+7mm2rvv/klTHTxWo5wv9h27TwaM63nWUeZmn777vhfdZ941inO0Sb/5Zp9z4pvG7vNaYxS/J0n/cyJ0N9RFNAAAAAAAm5lJcnop5bwk/5zktCSfGG1LAAAATKv25XgAAAAAAD3UWq9K8idJvpXke0m+XWv9u9F2BQAAwLSyEw0AAAAAMFS11v03+/j9Sd4/um4AAABgnp1oAAAAAAAAAACYehbRAAAAAAAAAAAw9SyiAQAAAAAAAABg6llEAwAAAAAAAADA1LOIBgAAAAAAAACAqWcRDQAAAAAAAAAAU88iGgAAAAAAAAAApp5FNAAAAAAAAAAATD2LaAAAAAAAAAAAmHrbbOmTpZT9tvT5Wuv3l7cdABhfchMAupObANCd3ASA7uQmAH1scRFNki8neUqS25LMPOJzc0kOHERTADCm5CYAdCc3AaA7uQkA3clNAJottYjmF5JcmOQttdZvDaEfABhnchMAupObANCd3ASA7uQmAM1WbOmTtdZ7k7wxyX8cTjsAML7kJgB0JzcBoDu5CQDdyU0A+lhqJ5rUWi9NcukQegGAsSc3AaA7uQkA3clNAOhObgLQaos70QAAAAAAAAAAwDSwiAYAAAAAAAAAgKlnEQ0AAAAAAAAAAFPPIhoAAAAAAAAAAKaeRTQAAAAAAAAAAEw9i2gAAAAAAAAAAJh6FtEAAAAAAAAAADD1LKIBAAAAAAAAAGDqWUQDAAAAAAAAAMDUm5mbmxvmeEMdDGCAZpbxsYb53LicfTNYMhOYFMudPXKTxchNYFKM61wzkZvjRG4Ck2Jcc1Nmjhe5CUwKudnRNsMcbGam/eubm5vLypUrm2o3btzYq3abbdq/TQ8//HC22267ptoHH3wwO+64Y/PYGzZsyM///OOban/84x/lcY/buan2pz+9N49//O5NtUnyox/dlac8pTTV3nBDzaGHHtY89jXXXN1cf801V+clL/nlptqvfOUfsvfe+zTVJsltt92aww9/elPtVVd9O0972uFNtd/97lU55JBDm2qT5Nprr8kBBxzYVLt27U3Zc88nNI99xx0/zKpVBzfVXn/9dc3jwmPRmptzc3O9M7c1+/rkXjKffdtuu21T7UMPPZSdd96lqfbee+9pfj5K5p+T+uRma9/JfO8HHfTkptobb/yn5vy57bZbc9ppb26qTZIPfvADOfroY5pq16y5NPvuu19T7S23fD9HHHFkU22SfOc7V+aww45oqr366u/0fp1y8MFPbaq97rrv9fpZn3DCLzbVJskFF/xjcy08Fn1yc8WK9k1aZ2dnm+tnZ2ez/fbbN9U+8MADvTO3db65YcOGHHjgQc1j33TTjb2+7p122qmp9r777mueIyfz8+RRzp322mvvptrbb78te+yxZ1PtnXfe0XuuuvvuezTV3nXXnb1yr+/vaJ/zKa0/q2T+5wXDMIrc7JOZm+r7nOPtm5t9Xk+3nsO6444fZp99nthUmyS33vqDXs9nrXOfZH7+0+fc2zHHHNdUe+mlFzfnXjKffX1ys8957b6Z2+c8a9/XSLvuultT7fr1dze/l/CjH93VVAeP1Ti+t7mpvs/7k33OD/d9Pdyafbfe+oPsttvPNY99990/6TVP7vNc2Hf+0idzn/GMo5tqr7hiTfO4m8ZunSdfe+01vd8j7PMaqc/v6C677NpUmyT33LO+1xyb7oa6iAYAAAAAAAAAAJZbKWXnJKuTnFxrXVdK+WiS5yS5b+Eu7661nrGlx7CIBgAAAAAAAACAsVVKOTbJh5Ks2uzwM5M8t9Z6e9fHad8/EwAAAAAAAAAARu+NSd6a5LYkKaXslGS/JB8qpVxVSnl3KWXJNTJ2ogEAAAAAAAAAYKtSStk1ya6LfGp9rXX95gdqracu1Gw6tGeS85K8Kck/J/lSkt/I/G41j8oiGgAAAAAAAAAAtjZvS/LORY6/O8m7tlRYa70pySmbbpdS/iLJ62IRDQAAAAAAAAAAY+b0JB9f5Pj6RY79G6WUw5KsqrV+fuHQTJKHlqqziAYAAAAAAAAAgK3KwiWbllww8yhmkpxeSjkv85dzOi3JJ5YqWtE4GAAAAAAAAAAAbHVqrVcl+ZMk30ryvSTfrrX+3VJ1dqIBAAAAAAAAAGDs1Vr33+zj9yd5/2OpX3InmlLKy0spv1VKOegRx097LAMBwKSTmQDQndwEgO7kJgB0JzcB6GOLi2hKKf8jyW8lWZVkdSnl32/26f97kI0BwDiRmQDQndwEgO7kJgB0JzcB6GupnWhemuRFtdbfSvLsJO8ppbxq4XMzA+0MAMaLzASA7uQmAHQnNwGgO7kJQC9LLaKZSTKXJLXWG5KcnOR/l1JO3HQcAEgiMwHgsZCbANCd3ASA7uQmAL0stYjms0nOL6UckyS11muSvCrJ3yc5aEuFADBlZCYAdCc3AaA7uQkA3clNAHrZ4iKaWuu7k7wryU83O/atJEcl+dhAOwOAMSIzAaA7uQkA3clNAOhObgLQ1zZL3aHW+vVFjt2S5G0D6QgAxpTMBIDu5CYAdCc3AaA7uQlAH0tdzgkAAAAAAAAAACaeRTQAAAAAAAAAAEw9i2gAAAAAAAAAAJh6FtEAAAAAAAAAADD1LKIBAAAAAAAAAGDqWUQDAAAAAAAAAMDU22bUDQAAAAAAAAA/q5Syc5LVSU6uta4rpZyW5LeTzCVZk+RNtdZ/eUTN65L8zyR3LBz6cq3194bYNgCMLYtoAAAAAAAAYCtTSjk2yYeSrFq4vSrJ7yY5KslPk3w8yVuTvO8Rpc9M8l9qrX83tGYBYEK4nBMAAAAAAABsfd6Y+UUyty3cfjDJm2ut99Za55JcnWS/ReqemeR1pZTvlFI+WUrZbTjtAsD4m5mbmxvmeEMdDGCAZpbxsYb53LicfTNYMhOYFMudPVtlbtpee+TkJjApxnWumZhvjhO5CUyKsczNhQUtuy7yqfW11vWPUrMuyYm11nWbHds9yWVJXl9rPf8R9z8jyf9IcmmSP06yX63115ah/WkkN4FJMZa5mRHMNYd6OaeZmfavb25uLitXrmyq3bhxY1asaNt0Z3Z2Ntts0/5tevjhh7Pddts11T744IPZbbefax777rt/ksc/fvem2h/96K7su+9ii5eXdsst38/RRx/TVJska9Zcmuc854Sm2gsvvKC572S+95NOekFT7bnnnp3DD396U+1VV327uXZT/fHHP7updvXqb+aVr3x1U+3nPveZPO95JzXVJsl5552bV73qNU21n/3sp5v7TuZ7L+WQptpar20eFx6L1tycm5trzr1kPvv6jL3ttts2j/3QQw815+7DDz+cnXfepan23nvvac7MZD43jzrqmU21l19+WY477vjmsS++eHWOOea4ptpLL704RxxxZFPtd75zZfPXnMx/3X36fsYzjm6qveKKNTnyyKOaapPkyisvzxvecGpT7cc+9uHeufniF5/cVPvVr34pv/Zrr2uq/du//escfPBTm2qT5LrrvtdcOy5sr7116JNd22+/ffO4DzzwwEjmmw8//HB23HHHptok2bBhQ6+56p57PqF57Dvu+GHzc/GVV16eQw45tKn22muvyQEHHNhUmyRr196Uww47oqn26qu/k6c97fDmsb/73at6zTcPPfSwptprrrm6+WtO5r/uPvPNPq9TTjzxeU21SXL++eflv/23dzTV/s//+cd5wQte1Dz22Wef1VwLj0Wf3BzlXLV1vvnQQw9lhx12aB77/vvvbz5Pe/fdP2nOzTvu+GGe9KT9m2qT5Oab1zWfp12z5tLeGXDCCb/YVHvBBf/Y/Fx69tln5dhjn9VUmySXXHJRr/zpM1d9yUt+uak2Sb7ylX/odV6i77npl770ZU21X/7ymb3eCxhjb0vyzkWOvzvJu7o8QCllnyRfTfKRRy6gSZJa6ymb3fdPk9zU0ij939scReZuqu8zV+2TuTvttFNTbZLcd9992WOPPZtq77zzjuy1197NY99++21Ztergptrrr7+ueezbb7+t+WtO5r/uPnPVffZ5YlPtrbf+oHmumczPN5///Bc21Z5zztfyO7/zX5vHfu97/7TX96z1fP7FF6/Ob//2f26qTZI///P3NZ9b+O53r2oedxoNdRENAADAuCil7Jpufx24aXvtv1m4/a/bay88zpa2135yKeW/Z34L7t+qtd69XP0DAACwVTo9839s8UiL7kLzSKWUg5OcleQvaq3vXeTzuyT59Vrrpj/kmEnyUFurADB9LKIBAABYXKe/Dqy1npokpZRNt29OcvPCsd2T/GaS1y/yOLfn326v/ZdJbK8NAAAwwRb+KKPTgplHKqU8LsnZSd5Ra/3ko9ztn5P811LK6lrrJZmfk57R1CwATCGLaAAAABbX968Dba8NAADAcjo1yZ5J3l5KefvCsTNrrX9YSvnwwsdnllJ+NckHSik7JLk+Sds1ngFgCllEAwAAsIiefx1oe20AAACWRa11/4UP37fwb7H7nLrZxxcmecbgOwOAybNi1A0AAABMks221/79xRbQLNi0vfaxC7dtrw0AAAAAMGJ2ogEAAFhettcGAAAAABhDFtEAAAAsA9trAwAAAACMN5dzAgAAAAAAAABg6llEAwAAAAAAAADA1Fvyck6llKckua/Welsp5dQkhyf5Zq317wfeHQCMEZkJAN3JTQDoTm4CQHdyE4A+trgTTSnlPyf5WpKLSikfTfKaJNcl+Y1Syh8MoT8AGAsyEwC6k5sA0J3cBIDu5CYAfS21E82vJ3lqkj2TXJPk8bXWB0opH05yWZL3DLg/gIk3Nzc3tLFmZmaGNtYUkpkAQyA3J4bcBBiwYWZmIjcHTG4CDJi55kSRmwADNum5ucWdaBY+/2Ct9eYk/6vW+sBmn1vyUlAAMEVkJgB0JzcBoDu5CQDdyU0AelkqLD6f5IJSyi/WWt+VJKWUI5J8KInrBgIsg9nZ2aGNtXLlyqGNNYVkJsAQyM2JITcBBmyYmZnIzQGTmwADZq45UeQmwIBNem5ucSeaWusfJvn9WuvGzQ4/kOSdtdZ3D7QzABgjMhMAupObANCd3ASA7uQmAH0tuW1ZrfUbj7hdk9SBdQQwZYZ9nXoGR2YCDJ7cnBxyE2CwZOZkkZsAgyU3J4vcBBisSc/NLe5EAwAAAAAAAAAA02DJnWgAGKxJX60JAMtJbgJANzITALqTmwDQ3aTnpp1oAAAAAAAAAACYenaiARixSV+tCQDLSW4CQDcyEwC6k5sA0N2k56adaAAAAAAAAAAAmHp2ogEYsUlfrQkAy0luAkA3MhMAupObANDdpOemnWgAAAAAAAAAAJh6dqIBGLHZ2dlRtwAAY0NuAkA3MhMAupObANDdpOemnWgAAAAAAAAAAJh6M0O+XtVkXxwLmCYzy/VAGzZsGNpz44477rhsfTNwMhOYFMuaPXKTRyE3gUkxlnPNRG6OGbkJTIqxzE2ZOXbkJjAp5GZHQ72c08xM+9c3NzfXXD83N5eVK1c21W7cuDE77rhjU22SbNiwIY973M5NtT/96b055pjjmse+9NKLc9JJL2iqPffcs/OTn9zdVPtzP7dbPvCBDzbVJsmb33xa3vGOP2iq/eM/fk9OOeWVzWOfccbnctRRz2yqvfzyy/K8553UVHveeefm+OOf3VSbJKtXfzP//t//x6baT37yE3nxi09uqv3qV7/Uu+/nP/+FTbXnnPO1vOENpzaP/bGPfTivetVrmmo/+9lPN48Lj0Wf3OubuStWtG1WNzs7m5122ql57Pvuu685dzds2JCXv/wVTbVf/OIXmms31fdx/vnfaK498cTnNj8Xr179zbz61a9tqv3MZz6VZzzj6KbaJLniijV56Utf1lT75S+fmWOPfVZT7SWXXJTTTntzU22SfPCDH+j1+qo195L57HvZy05pqj3zzDPy67/+xqbaj370Q80/q2T+5wXDMK65ud122zXVPvjgg70zt5RDmmprvTYveckvN4/9la/8Q57ylNJUe8MNNe9613uaat/1rj/IkUce1VSbJFdeeXmvOURrdiXz+XXyyS9vqv3Sl76YVasObqq9/vrr8pznnNBUmyQXXnhBr3lyn8zt+zva53VK6/w8mZ+jwzCMIjf7nKNN5s/Tbr/99k21DzzwQHbYYYfmse+///4cdtgRTbVXX/2dXs8pT3va4U21SfLd716V97//r5pq3/KWN/V+Pms9d/exj3241zz3uOOOb6pNkosvXp2DD35qU+11130vz33uiU213/jG+c1Zn/TP+77fsz5z9Be96KVNtWed9eWmOnisRvneZutcM5mfb+688y5Ntffee89I39vs835X67mzZP782W/8xmlNtR/5yAfz6U9/tqn2Na95Ve9zb8961i801V500bd61baeV0jmzy0cffQxTbVr1lza+3VK6+/ppZde3OucxqGHHtZUmyTXXHN181z3K1/5h+Zxp5HLOQEAAAAAAAAAMPWGuhMNAD9ruFfVA4DxJjcBoBuZCQDdyU0A6G7Sc9MiGgAeVSll5ySrk5xca11XSjktyW9n/jqwa5K8qdb6L6PsEQAAAAAAAGA5WEQDMGJzW+lyzVLKsUk+lGTVwu1VSX43yVFJfprk40nemuR9I2oRgCm0teYmAGxtZCYAdCc3AaC7Sc/NFaNuAICt1hszv0jmtoXbDyZ5c6313lrrXJKrk+w3quYAAAAAAAAAlpOdaABGbJirNUspuybZdZFPra+1rt/8QK311IWaTbdvTnLzwrHdk/xmktcPsF0A+BmT/lcOALBcZCYAdCc3AaC7Sc9NO9EATJe3JVm7yL+3dX2AUso+Sb6e5CO11vMH0CMAAAAAAADA0NmJBmDEZmdnhznc6Uk+vsjx9Ysc+xmllIOTnJXkL2qt713GvgCgkyHnJgCMLZkJAN3JTQDobtJz0yIagCmycMmmTgtmHqmU8rgkZyd5R631k8vaGAAAAAAAAMCIWUQDMGJjdN3AU5PsmeTtpZS3Lxw7s9b6hyPsCYApM0a5CQAjJTMBoDu5CQDdTXpurngsdy6luHQHwJSpte5fa11Xa31frXW7WuvTN/tnAc0WyE0A6E5uAkB3chMAupObADwWj7oTTSnlo4scflkpZbckqbX++sC6Apgik75ac1rITYDhkJuTQW4CDJ7MnBxyE2Dw5ObkkJsAgzfpubmlyzn9OMl/TPJHSdYvHPulJBcMuikAGENyEwC6k5sA0J3cBIDu5CYAvTzq5Zxqrb+b5N8leU2Sm2utn0jyk1rrJxY+BmAZzM3NDe0fgyM3AYZDbk4GuQkweMPMTLk5WHITYPBk5uSQmwCDN+m5+aiLaJKk1vr1JC9N8pZSyv9KsnIoXQHAGJKbANCd3ASA7uQmAHQnNwHoY0uXc0qS1Fp/kuRXSymnJjl88C0BTBd/fTBZ5CbAYMnNySI3AQZna87MUsrOSVYnObnWuq6UclqS304yl2RNkjfVWv9llD1ujeQmwOBszblJG7kJMDiTnptLLqLZpNb64SQfHmAvADAx5CYAdCc3AaZHKeXYJB9Ksmrh9qokv5vkqCQ/TfLxJG9N8r4RtbjVk5sA0J3cBOCx2uLlnAAAAAAAltEbM79I5raF2w8meXOt9d5a61ySq5PsN6rmAAAAmG6dd6IBYDBmZ2dH3QIAjA25CQDdDDszSym7Jtl1kU+tr7Wu33Sj1nrqwv033b45yc0Lx3ZP8ptJXj/gdgHg3zDXBIDuJj037UQDAAAAAPT1tiRrF/n3ti7FpZR9knw9yUdqrecPqEcAAADYIjvRAIzY3NzcqFsAgLEhNwGgmxFk5ulJPr7I8fWLHPs3SikHJzkryV/UWt+7zH0BwJLMNQGgu0nPTYtoAAAAAIBeFi7ZtOSCmUcqpTwuydlJ3lFr/eSyNwYAAACPgUU0ACM26as1AWA5yU0A6GaMMvPUJHsmeXsp5e0Lx86stf7hCHsCYMqMUW4CwMhNem5aRAMAAAAADFWtdf+FD9+38A8AAABGziIagBGb9NWaALCc5CYAdCMzAaA7uQkA3U16bs4M+Quc7O8mME1mluuBfvjDO4b23PiEJ+y5bH0zcDITmBTLmj1yk0chN4FJMZZzzURujhm5CUyKscxNmTl25CYwKeRmR0PdiWZmpv3rm5uby8qVK5tqN27cmB122KGp9v77789ee+3dVJskt99+W1772v/QVPupT/1NDjjgwOax1669KXvvvU9T7W233ZojjjiyqfY737kyBx/81KbaJLnuuu8111933ffy3Oee2Dz2N75xfq+x99//gFX7Y0EAACAASURBVKbadevW5rjjjm+qTZKLL16dE074xabaCy74xxxyyKFNtddee03vn/WRRx7VVHvllZc3126qX7Xq4Kba66+/rnncxUz6ak3ateZmn8xMRp+bxxxzXFPtpZdenMMOO6Kp9uqrv5Pdd9+jqTZJ7rrrzjzlKaWp9oYbako5pHnsWq/Ns5/93Kbab37zG72eh/u+TmmtX7v2pjzrWb/QVHvRRd/KKae8sqk2Sc4443M56aQXNNWee+7ZOfTQw5rHvuaaq3Pssc9qqr3kkovyjGcc3VR7xRVrmjMzkZsMT5/cXLFiRfO4s7OzzfWzs7PZZZddm2rvuWd9Tj755U21SfKlL30xxx//7Kba1au/2TvvW+c/F1+8Ok960v5NtTffvK75a07mv+7DD396U+1VV307Bx54UPPYN910Y6/5y8tedkpT7ZlnntF7jt1a/41vnN9rrto6R07m58l9Xle2Zm4yn7vLRWayJX1ys09ta+4l89m37777NdXecsv38/znv7B57HPO+Vpe8IIXNdWeffZZvfrue/6rz5zvqKOe2Tz25Zdf1jz/ueaaq5vHvvzyy/Kc55zQVJskF154QX71V/9dU+3f//3f5eijj2mqXbPm0ubsSebzp0/en3ji85rHPv/883r9nj3veSc11Z533rlNdY9GbvJo+r632We+uNNOOzWPfd9992X77bdvqn3ggQfyohe9tKn2rLO+3Pw6Ppl/Ld/nvba+udk617399tt6nXvrmwF93g/uc46277yr9fXZOed8rfdctc/rlD7nNF7xilc11SbJF77w2V59L6dJz832M4UAAAAAAAAAADAhhroTDQA/a3Z2dtQtAMDYkJsA0I3MBIDu5CYAdDfpuWknGgAAAAAAAAAApp6daABGbNKvGwgAy0luAkA3MhMAupObANDdpOemnWgAAAAAAAAAAJh6dqIBGLFJX60JAMtJbgJANzITALqTmwDQ3aTnpp1oAAAAAAAAAACYehbRAAAAAAAAAAAw9VzOCWDEJn3LMwBYTnITALqRmQDQndwEgO4mPTftRAMAAAAAAAAAwNTb4k40pZRn1lovW/j4l5K8JMlDSc6otV4yhP4AJt6kr9acFjITYDjk5mSQmwCDJzMnh9wEGDy5OTnkJsDgTXpuLrUTzV8lSSnlrUlOT3JLkjuS/FUp5TcH3BsAjBOZCQDdyU0A6E5uAkB3chOAXra4E81m3pjkxFrrj5OklPLhJJcl+ctBNQYwLWZnZ0fdAstLZgIMkNycOHITYEBk5kSSmwADIjcnktwEGJBJz82ldqLZtpSyIsmdSe7b7Pi/JJns7wwAPDYyEwC6k5sA0J3cBIDu5CYAvSy1iOauzG9z9tQk/2+SlFKel+RbST472NYApsPc3NzQ/jFQMhNgCOTmxJCbAAM2zMyUmwMnNwEGTGZOFLkJMGCTnptbvJxTrfV5SVJKKUl2Wzj8YJJ31lq/PODeAGBsyEwA6E5uAkB3chMAupObAPS1xUU0m9Ra62Yff2tw7QBMH399MFlkJsBgyc3JIjcBBkdmTh65CTA4cnPyyE2Awdmac7OUsnOS1UlOrrWuK6WcluS3k8wlWZPkTbXWf9nSYyx1OScAAAAAAAAAANhqlVKOTfLNJKsWbq9K8rtJjk9yeObXx7x1qcfptBMNAIOzFS/WBICtjtwEgG5kJgB0JzcBoLutODffmPlFMn+zcPvBJG+utd6bJKWUq5Pst9SDWEQDAAAAAAAAAMBWpZSya5JdF/nU+lrr+s0P1FpPXajZdPvmJDcvHNs9yW8mef1SY1pEAzBiW/N1AwFgayM3AaAbmQkA3clNAOhuyLn5tiTvXOT4u5O8q8sDlFL2SfLVJB+ptZ6/1P0togEAAAAAAAAAYGtzepKPL3J8/SLHfkYp5eAkZyX5i1rre7vUWEQDMGKzs7OjbgEAxobcBIBuZCYAdCc3AaC7YebmwiWbOi2YeaRSyuOSnJ3kHbXWT3ats4gGAAAAAAAAAIBJcmqSPZO8vZTy9oVjZ9Za/3BLRRbRAAAAAAAAAAAw9mqt+y98+L6Ff4/JzNzc3LI2tIShDgYwQDPL9UDXXXf90J4bDz541bL1zcDJTGBSLGv2yE0ehdwEJsVYzjUTuTlm5CYwKcYyN2Xm2JGbwKSQmx0NdSeamZn2r29ubq65fm5uLitXrmyq3bhxY37+5x/fVJskP/7xj7L33vs01d5226058MCDmse+6aYbc+yxz2qqveSSi/Kc55zQVHvhhRfkl37p+U21SfL1r5/T/HXfdNONefObf7N57A984C9z0kkvaKo999yz86IXvbSp9qyzvpzjjju+qTZJLr54dU455ZVNtWec8bk861m/0FR70UXfyvOf/8Km2iQ555yv5SUv+eWm2q985R9y5JFHNY995ZWX55BDDm2qvfbaa5rHhceiT+6tWLGiedzZ2dnssMMOTbX3339/Djroyc1j33jjP2X33fdoqr3rrjt7/b9+xjOObqpNkiuuWJPDD396U+1VV327OT+S+Qw5/vhnN9WuXv3NXrnX+jojmX+t0ScDTjjhF5tqL7jgH/PiF5/cVJskX/3ql5qz75xzvpYTT3xe89jnn39eTj755U21X/rSF3v9/9h33/2aapPkllu+31wLj0Wf3Nx2222bx33ooYeyzTZtU+uHH364eb754x//KEcffUxTbZKsWXNp9tzzCU21d9zxw965+bKXndJUe+aZZ+R1r3tDU+1f//XH8pSnlKbaJLnhhtpr7tR3/vKKV7yqqfYLX/hs3vSmtzTV/tVfvb953E1jt/6erllzaX7t117XVPu3f/vXza8zkvnXGoceelhT7TXXXN2cuYn5JsMzivnm7Oxsdt11t6baJFm//u7ss88Tm2pvvfUHzXPNZH6+2ec8a58526/8yv/VVJsk/+f/fL7X/KXv89krX/nqptrPfe4zveZ8ra8VkvnXC69+9Wubaj/zmU/lVa96TVPtZz/76bz2tf+hqTZJPvWpv+l1brp1rpnMzzf7nBPpk7kwDH3f2+zz/mRr7ab6PudZ+9TutdfeTbVJcvvtt2XVqoObaq+//rr83u9t8QotW/RHf/T/5KijntlUe/nll/Xqu+/7qn1ys8/54Te84dSm2iT52Mc+3Pze6MUXr+59XqLPHLtP7h1wwIFNtUmydu1N2X//A5pq161b2zzuNHI5J4ARG/KOYAAw1uQmAHQjMwGgO7kJAN1Nem62/5k6AAAAAAAAAABMCDvRAIzYpK/WBIDlJDcB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yFOeUppqk+SGG2p+/ucf31T74x//KHvvvU/z2Lfddmtz7zfcULP77ns01d511515/ON3b6pNkh/96K7suutuTbXr19+dXXbZtXnse+5Z32vsgw56clPtjTf+U570pP2bapPk5pvXZd9992uqveWW72effZ7YVHvrrT/IHnvs2VSbJHfeeUce97idm2p/+tN7s9tuP9c89t13/yQ777xLU+29997TPC48Fq252Sczk/nc3HbbbZtqH3rooaxadXDz2Ndff10OOODAptq1a2/qlbmt424au/X58M4772jO3GQ+d/s8j++1195NtbffflvvzG3NvptvXpcDDzyoqfamm27snbl9+t5zzyc0j33HHT/MTjvt1FR73333Nf+87rlnffO4m8aGYRhlbm633XZNtQ8++GCv5/DWOUAyPw/ok12tc59kfv7TZ+w+r+Of+MR9m2qT5Ac/uKVX361zzWR+vtkn+/q8vur7e9bn3EKf2r5z1T5jt/6OJuabDE+f3Nxmm7ZTyg8//HDv/x99XtPuv/8BzWOvW7e2V/70OW/X99x0n+zqO+drPXd3990/6fWz7vs965ObffK6tXZTfet88447ftj7PGufn1ef8/EwDH3f21y5cmVT7caNG7PDDjs0j33//ff3yq5RnjPsc/6r9T2nZP59pz7PSX2+Z621m+r7/Kz75F7fc+p9zom0vheQzL8f0Oe9hD6/o33/X/dZ80B3Q11EA8DPGvKOYJ2VUv57kjckeTDJZ2qtfzTilgBgq81NANjayEwA6E5uAkB3k56b7X9uB8DEKqWclOS1SZ6Z5Mgkx5ZSXjHargAAAAAAAAAGx040ACM2Ozs76hYWc2SSr9Va702SUspZSX4lyRdG2hUAU28rzU0A2OrITADoTm4CQHeTnpsW0QBMkVLKrkkWuyDp+lrr+s1uX5HkfaWUP0myIcnLYvcyAAAAAAAAYIJZRAMwYkO+buDbkrxzkePvTvKuTTdqrV8vpXw8yflJfpLk3CTHDb49ANiySb/eLgAsF5kJAN3JTQDobtJz0yIagOlyepKPL3J8811oUkp5XJIv1Fr/bOH2f0ly48C7AwAAAAAAABgRi2gARmyYqzUXLtm0fsk7Jgck+etSytFJdkpyapI3DrI3AOhi0v/KAQCWi8wEgO7kJgB0N+m5uWLUDQCw9am1XpXk80muSnJpkj+v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K+ZlNzVz3tFNoCt0s6U5vZ3TggX1n9/09HRWWKFu45ypqamsvPLKVbO333571lhjzarZJPnlL2/KBhtsWDV79dW/SNM8snrtUn6cjTbauGr2yiuvyLrrrlc1e9111+be97531WyS/PGPf8x6661fNXvttddkrbXWrl77xhtvyDbbbFs1e+65Z+dVrzqgavaooz6UD33oqKrZJDnggFflhBNOqprdY4/dcsghh1XNHnHEO/Oyl+1bNZskn/jE0dl556dXzZ566tez2257VK990kknDPW1hrlQ283p6emsuOKK1esuWbJkqG7Wtifp9WeYbm666aOqZi+77EdD936Y5t73vverXvvmm3+fRz96YdXspZcuzjrrrFs1e/3112XLLbeqmk2SCy9clFe/+rVVsx/+8AfzkY8cXTW7//775sQTv1Q1myS7777rUMddO3vn/DOesUvV7Ne+dnL23PMFVbPHH/+56r/jJL2/58BcGKabw56rrrbaalWzt956ax7wgAdWzf72t7+p7l7Sa98wfxffZJOmeu2f/rRk8823qJq9+OKLhjpfrJ0ddv7aa6/JrrvuXr32l750YnbZZdeq2ZNP/lIOP/xdVbOHHnpwjjnmuKrZJNl7772y1157V80ed9wxefnL96ua/fjHP5p9992/ajZJjj76I3nWs55TNXvKKV/ODjv8XfXaZ5757epZGMQ4zjeXLFmSVVZZpWo2SW677bY86EEPrpr99a9/NfT5yyMfuVnV7I9//MOhXmetPUdOeufJ87WbW2+9TdXs+eefm5e85KVVs0ly7LGfzBe/+JWq2ec+99m5+OLvV81uvvljq7uX9Nr3/Oe/qGr285//THX3kl77jjzy/VWzb3jDQdVfr2OP/WTVHAxq2PPFYZpb+xpt0nudds0116qavemmG4d6vbG2e0mvfbWv0/7ylzcNfa56n/vct2r2D3+4ORtv/LCq2SuuuHzo3u+++55VsyeeeHxe8YpXVs1+7GP/k7e//Z1Vs0nylrccVn2+uffee+UFL9ireu3Pfe64PPOZz66a/epXv5IDD3x91ewHPvDeoV8beMpTdqqaPf3006rXnURzehENAH9rjncEA4B5TTcBoB3NBID2dBMA2ut6N+u2dgEAAAAAAAAAgA6xEw3AmHX9ak0AmE26CQDtaCYAtKebANBe17tpJxoAAAAAAAAAACaenWgAxqzrV2sCwGzSTQBoRzMBoD3dBID2ut5NO9EAAAAAAAAAADDx7EQDMGZTU1PjPgQAmDd0EwDa0UwAaE83AaC9rnfTTjQAAAAAAAAAAEw8F9EAAAAAAAAAADDx3M4JYMymp6fHfQgAMG/oJgC0o5kA0J5uAkB7Xe+mnWgAAAAAAAAAAJh4dqIBGLOuX60JALNJNwGgHc0EgPZ0EwDa63o3l7kTTdM0X26aZuO5OhgAmM90EwDa000AaE83AaA93QRgGDPdzmnrJN9omuZNTdOsPBcHBDBppqen5+wXI6ebACOmm52imwAjNJfN1M05oZsAI6SZnaObACPU9W7OdBHNtUm2TfLYJD9rmubQpmkeMvrDAoB5STcBoD3dBID2dBMA2tNNAKqtNMP7p0spNybZu2maTZLsl+SbTdOsmuSaUso2Iz9CgI7zrw86RTcBRkw3O0U3AUZIMztHNwFGSDc7RzcBRqjr3ZzpIpoFd/5HKeWnSd6c5M1N0zwoiXsJAsBf000AaE83AaA93QSA9nQTgGozXUTzT/f0xlLKr5P8evYPB2DyTE0tGfchMHt0E2DEdLNTdBNghDSzc3QTYIR0s3N0E2CEut7NmS6i+WHTNBsu7Z2llF/M8vEAwHymmwDQnm4CQHu6CQDt6SYA1Wa6iOaUJJskuS532fqsbzq2PAMYWtfvGzhhdBNgxHSzU3QTYIQ0s3N0E2CEdLNzdBNghLrezZkuonlykrOSvKaUcs4cHA8AzGe6CQDt6SYAtKebANCebgJQbYVlvbOUcnOS/ZLsMzeHAzB5pqen5+wXo6WbAKOnm92hmwCjNZfN1M3R002A0dLMbtFNgNHqejdn2okmpZRFSRbNwbEAwLynmwDQnm4CQHu6CQDt6SYAtWa8iAaA0fKvDwCgPd0EgHY0EwDa000AaK/r3Vzm7ZwAAAAAAAAAAGASLJjjq4S6fUkSMEkWzNYHeuhDN5qz58arrrpy1o6bkdNMoCtmtT26yVLoJtAV8/JcM9HNeUY3ga6Yl93UzHlHN4Gu0M2W5vR2TgsW1H9+09PT1fPT09NZeeWVq2Zvv/32PPjBa1TNJsmvfvXLPP3pz6qa/frXT6mevXN+iy2eUDV70UXfzcYbP6xq9oorLs9DH7pR1WySXHXVlXnYwx5eNXv55T+rPu6kd+xPetKTq2bPO++c7LXX3lWzxx13TG644caq2SRZe+21cuaZZ1XN7rDDdtXrJsmSJUuqZ1dcccWce+75VbPbbLN1Fi++tHrthQsfnV/84uqq2Q033KB63XvS9S3PqDdM94Zt7iqrrFI1e9ttt2WttdauXvvGG2/IDjv8XdXsmWd+e6jmPvGJT6qaTZILLjhvqHYN+3eN9deve1665pqrh5qt/XtG0vu7xnbb7VA1e9ZZZ+bYYz9TNfuSl7woJ5305arZJNltt+fk1FO/VTW7885PzYUXfq967S23fHzOO++CqtknPemJWbTowqrZrbbasmpuVHSTpRlnN1daqe7U+o477shGG21cNXvllVdUP48mvefS7bffsWr2O985Y+gGDNPNNddcq2r2pptuzDrrrFs1myTXX3/dUOfJ2267ffXaZ5/9nWyzzbZVs+eee3bOP39R1ezWW2+V973vg1WzSfK61702n/3sF6pmX/jC5+WWW26tml199dXy/vd/qGo2SQ466IBcdNHFVbNbbLF5fvOb31av/cAHPqB69u40k2UZppsrrFC3ufnU1FT1a7RJ73Xarbbaump20aLzs+6661Wvfd1112azzR5TNfvDH/5gqON+xCM2rZpNkp/85LI85CEPrZr9+c+vqj5fTHrnjMP0fpjXBvbc8wVVs0ly/PGfy7vedWTV7MEHv2Gsrzd+/evfrJp7+tOflu985+zqdbffftt84AP/XTV74IGvqV53tukmSzPOn23Wvkab9F6nfcADHlg1+9vf/iaPfvTCqtlLL12czTffomo2SS6++KKh1q49x05659m1P9+86qorq883r7/+uixc+Liq2SRZvPiS6te2L7jgvOy++55VsyeeeHz1zyaT3s8n3/veD1TNvv71B1ave6dhen/yyV+rmt1ll2fki1/8StVskjz3uc+unp1tXe+m2zkBAAAAAAAAADDx5nQnGgD+1tTU1LgPAQDmDd0EgHY0EwDa000AaK/r3bQTDQAAAAAAAAAAE89ONABj1vX7BgLAbNJNAGhHMwGgPd0EgPa63k070QAAAAAAAAAAMPHsRAMwZl2/WhMAZpNuAkA7mgkA7ekmALTX9W7aiQYAAAAAAAAAgIlnJxqAMev61ZoAMJt0EwDa0UwAaE83AaC9rnfTTjQAAAAAAAAAAEw8O9EAjFnXr9YEgNmkmwDQjmYCQHu6CQDtdb2bdqIBAAAAAAAAAGDi2YkGYMympqbGfQgAMG/oJgC0o5kA0J5uAkB7Xe/mMi+iaZpmpSR7J/ljkhOSHJlkhyTfTXJwKeU3Iz9CAJgndBMA2tNNAGhPNwGgPd0EYBgz7URzdJLVk6ya5MAkFyR5fpJdk/xPkj1GenQAE6Dr9w2cMLoJMGK62Sm6CTBCmtk5ugkwQrrZOboJMEJd7+ZMF9E8vpSysGmaFZNcU0rZpv/2HzVNc8mIjw0A5hvdBID2dBMA2tNNAGhPNwGotsIM759qmuYRSR6f5H5N0zw0SZqmWSPJyiM+NgCYb3QTANrTTQBoTzcBoD3dBKDaTDvRvDnJaeldbPPCJF9rmuYHSbZK8i8jPjaAidD1Lc8mjG4CjJhudopuAoyQZnaObgKMkG52jm4CjFDXu7nMi2hKKacm2fDO3zdNc36S7ZL831LKZSM+NgCYV3QTANrTTQBoTzcBoD3dBGAYy7yIpmmaDe/hzYvufF8p5RcjOSqACdL1qzUniW4CjJ5udoduAoyWZnaLbgKMlm52i24CjFbXuznT7ZxOSbJJkuuSLLjb+6aTbDyKgwKAeUo3AaA93QSA9nQTANrTTQCqzXQRzZOTnJXkNaWUc+bgeAAmTtev1pwwugkwYrrZKboJMEKa2Tm6CTBCutk5ugkwQl3v5grLemcp5eYk+yXZZ24OBwDmL90EgPZ0EwDa000AaE83ARjGTDvRpJSyKP37BAIw++o/lDQAABRESURBVKampsZ9CMwi3QQYLd3sFt0EGB3N7B7dBBgd3ewe3QQYna53c5k70QAAAAAAAAAAwCSYcScaAEar6/cNBIDZpJsA0I5mAkB7ugkA7XW9m3aiAQAAAAAAAABg4i2Y46uEun1JEjBJFszWB7rf/e4/Z8+Nv//972btuBk5zQS6Ylbbo5sshW4CXTEvzzUT3ZxndBPoinnZTc2cd3QT6ArdbGlOb+e0YEH95zc9PZ0VVqjbOGdqaiorrrhi1eySJUuyxhprVs0myS9/eVMWLnxc1ezixZdkq622rl570aLzs8suu1bNnnzyl/L4x29ZNfu971049J/ZZps9pmr2hz/8QQ4++NDqtd/1rsNzzDHHVc3uvfdeueiii6tmt9hi86q5u7r++huq5tZZZ+2ccMJJVbN77LFbPvSho6pmk+SAA16VZz7z2VWzX/3qV6pn75w/+uhPVM3uu+/LqteFQdR2c3p6OiutVJ/4O+64Y6hurrXW2tVr33jjDXnEIzatmv3JTy7L9tvvWDX7ne+cUd29pNe+LbZ4QtXsRRd9NxtttHH12ldeeUU22aSpmv3pT0v+8R//uWr2He/4j3zhC/9bNZskz3veP+TWW2+tml1ttdWq102SW26pWzdJVl99tXzkI0dXze6//7458sj3V6/9hjcclGc96zlVs6ec8uU87Wl/XzX7zW9+I+9+93urZpPkTW96ffUsDGKc3Vx11VWrZv/0pz9lzTXXqpq96aYbs912O1TNJslZZ52ZbbbZtmr23HPPzk477Vy99mmnnZrHPrbuHOj737846667XtXsddddW93rpNfsQw/9p6rZww//zxxxxHuq1z7kkDdWzw7rmmuurZ5df/318rGPfbJq9hWveGle97q6z/t973tPdt1196rZJPnSl07MU56yU9Xs6aeflle/+rXVa3/4wx+snoVBDNPNYc4Xh/m7/K233ppVVlmlava2227Lpps+qnrtyy77UZrmkVWzpfx4qNdZhz1fXG+99atmr732mqy//gbVa19zzdXZeuttqmbPP//cHHXUR6tmX/Wq/armlgfHHvuZ6tmXvORF+dSnPl01u88+L86LX7xP9dqf/vSnhnqN9/DD31U1e+ihB1fNwaCG/dlm7fnmHXfcMfS56v3v/4Cq2d/97rfVDbjmmquHfp219nzztNNOzcMe9vDqtS+//GfV85df/rPstdfeVbPHHXdMnvSkJ1fNJsl5552TQw45rGr2iCPeOVRzr776mqrZJNlgg/Vz4YXfq5rdcsvH57DD3lK99jvf+fa88Y2HVM2+5z1HDPVziNpzzaR3vvna176uavaDH3xf9bqTaE4vogHgb3X9voEAMJt0EwDa0UwAaE83AaC9rnezbmsXAAAAAAAAAADoEDvRAIxZ16/WBIDZpJsA0I5mAkB7ugkA7XW9m3aiAQAAAAAAAABg4rmIBgAAAAAAAACAied2TgBjNjW1ZNyHAADzhm4CQDuaCQDt6SYAtNf1btqJBgAAAAAAAACAiWcnGoAxm56eHvchAMC8oZsA0I5mAkB7ugkA7XW9m3aiAQAAAAAAAABg4tmJBmDMun61JgDMJt0EgHY0EwDa000AaK/r3bQTDQAAAAAAAAAAE89ONABj1vWrNQFgNukmALSjmQDQ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\n", 199 | "text/plain": [ 200 | "
" 201 | ] 202 | }, 203 | "metadata": { 204 | "needs_background": "light" 205 | }, 206 | "output_type": "display_data" 207 | }, 208 | { 209 | "data": { 210 | "text/plain": [ 211 | "
" 212 | ] 213 | }, 214 | "metadata": {}, 215 | "output_type": "display_data" 216 | }, 217 | { 218 | "data": { 219 | "text/plain": [ 220 | "
" 221 | ] 222 | }, 223 | "metadata": {}, 224 | "output_type": "display_data" 225 | }, 226 | { 227 | "data": { 228 | "text/plain": [ 229 | "
" 230 | ] 231 | }, 232 | "metadata": {}, 233 | "output_type": "display_data" 234 | }, 235 | { 236 | "data": { 237 | "text/plain": [ 238 | "
" 239 | ] 240 | }, 241 | "metadata": {}, 242 | "output_type": "display_data" 243 | }, 244 | { 245 | "data": { 246 | "text/plain": [ 247 | "
" 248 | ] 249 | }, 250 | "metadata": {}, 251 | "output_type": "display_data" 252 | } 253 | ], 254 | "source": [ 255 | "# different windows sizes for sentiment score b\n", 256 | "#h = 24\n", 257 | "s_days = 20 # short\n", 258 | "l_days = 20 # long\n", 259 | "\n", 260 | "f, axes = plt.subplots(1, 5, figsize=(40,10))\n", 261 | "win_all_a = np.zeros(shape=(s_days,l_days))\n", 262 | "# matrix of size (s_days,l_days)\n", 263 | "for std in range(0,5):\n", 264 | " for i in range(0, s_days):\n", 265 | " for j in range(0, l_days):\n", 266 | " sent_score_a = ah.nb_calc_sentiment_score_a(aug_signal_a,aug_signal_b,(i+1)*24+np.random.normal(0,std),(j+1)*24+np.random.normal(0,std))\n", 267 | " win_all_a[i,j] = ah.nb_backtest_a(price_data, sent_score_a, 1.0, 0.0075)[-1]\n", 268 | " cmap = sns.cubehelix_palette(50, hue=0.05, rot=0, light=0.0, dark=1.2, as_cmap=True)\n", 269 | " figure(num=None, figsize=(10, 7), dpi=80, facecolor='w', edgecolor='k')\n", 270 | " ax = sns.heatmap(win_all_a, linewidth=0.01, cmap=cmap,ax=axes[std])\n", 271 | "plt.show()\n" 272 | ] 273 | }, 274 | { 275 | "cell_type": "code", 276 | "execution_count": 13, 277 | "metadata": {}, 278 | "outputs": [ 279 | { 280 | "data": { 281 | "image/png": "iVBORw0KGgoAAAANSUhEUgAACNEAAAJBCAYAAABiALHAAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4xLjAsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy+17YcXAAAgAElEQVR4nOzde5SsZX0n+m/vDcPFA2wiiNyUi/CACIggt8hlEC9RYjSjMfEkxiiaYzQZTmJmMk5uLieTmTmTSCY5yZl4CR5dSbxiiCgqMNxBBBEQ4YFwE9iIoG4gIAi7+/zRvbP22Ta7X563q6qr6vNZq9fqeqt/9fyqL/Wtp+rp552Zm5sLAAAAAAAAAABMs1WjbgAAAAAAAAAAAEbNIhoAAAAAAAAAAKaeRTQAAAAAAAAAAEw9i2gAAAAAAAAAAJh6FtEAAAAAAAAAADD1LKIBAAAAAAAAAGDqbTHMwWZmZuZaa+fm5jIzMzNWtdM69rj2vRxjr1rVti5tdnZ2LL9no/5+j3LsJO2DL3KTy3hbS1nOvhmsuXH9+xjHsce171GOvRx9jyI3x/X7Pcqxl6Hv5c4euclipi43x7XvUY49rn2Pcmx9j2TscZ1rJnJznIwkN8f8b9Pj2ZiMvRx9r169uql2/fr1I3ltOZnOebLXaBmWcXxvc5Rjj2vfoxx7nPse5+yaxtemIzc7sxMNAAAAAAAAAABTzyIaAAAAAAAAAACmnkU0AAAAAAAAAABMPYtoAAAAAAAAAACYeluMugEAVq5SyvZJLktySq31jlLKR5Icl+SRhS95X631zJE1CAArhMwEAAAAABh/FtEAsKhSylFJPphk/40OvzjJ8bXWe0fTFQCsPDITAAAAAGAyOJ0TAE/l7UnelWRtkpRSnpHkOUk+WEq5rpTyvlKKHAEAmQkAAAAAMBHsRAMwRUopa5KsWeSqdbXWdRsfqLWeulCz4dAuSc5P8qtJ/jnJ55O8LfP/eQ8AE6drbspMAAAAAIDJYBENwHQ5LckfLHL8fUn+cHOFtdbbkrxuw+VSyp8neXO8IQjA5GrKTZkJAAAAADCeLKIBmC6nJzljkePrFjn2/1NKOTjJ/rXWzywcmknyxPK1BgArTlNuykwAAAAAgPG05CKaUsoBSV6fZI8ks0nWJjmn1nrVgHsDYJktnHpiyQUzT2EmyemllPMzf2qKdyT56HL1NglkJsBk6ZGbMrMDuQkA3clNAOhObgLQx6rNXVlK+bUkf79w8WtJrl74/IOllN8aZGMArCy11uuS/HGSS5N8K8k3aq1/N9quVg6ZCcAGMnNpchMAupObANCd3ASgr5m5ubmnvLKUcnOSF9ZaH93k+LZJvl5rPeBpDTYz89SDLWFubi4zMzNjVTutY49r38sx9qpVm12X9pRmZ2fH8ns26u/3KMfO/H+YL5fmx8YGy9k3G1nuzEwyN65/H+M49rj2Pcqxl6PvUeTmuH6/Rzn2MvS93NkjNyeA3Bxt7bSOPa59j3JsfY9k7HGdayZyc2AmJTfH/G/T49mYjL0cfa9evbqpdv369SN5bTmZznmy12h5Kt7bHO3Y49r3KMce577HObum8bXpyM3OlvrteCLJlosc32bhOgBgnswEgO7kJgB0JzcBoDu5CUAvWyxx/R8luaaUcl6SexeO7ZrkpCT/cZCNAcCYkZkA0J3cBJhipZTtk1yW5JRa6x2llI8kOS7JIwtf8r5a65kja3DlkZsA0J3cBKCXzZ7OKUlKKbslOTnJbpnfKueeJOfWWtc+7cHGcMuzUW+rNI5jj2vfyzG20zlNz9ix5RmLWM7MzBSelmKUY49r36Mc25aZ0zP2CjstRSI3J4bcHPnf5tSNPa59j3JsfY9k7HGdayYdc7OUclSSDyY5IMn+C4tork/y8lrrvZuvnl6TkJtj/rfp8WxMxnY6p7axx/VnHa/R8hSm/b3NUY49rn2Pcuxx7nucs2saX5uO3Ow+4FKLaJZ1sDEMmlH/Mo/j2OPa93KMbRHN9IwdQcPgTd2bgaMce1z7HuXYJirTM/YKezMwkZssbupyc1z7HuXY49r3KMfW90jGHte5ZkopOyZZs8hV62qt6zb6ug8l+WiSjyU5Mcn9SdYmuTjJc5KcmfmdaGYH3fMUs4hmTMYe175HObZFNG1jj+vPOl6jZQjG8b3NUY49rn2Pcuxx7nucs2saX5uO3Oys/TcbAAAAAGDeaUluX+TjtI2/qNZ6aq314o0O7ZLk/CRvTXJ05k/r9LZhNAwAAACb2mLUDQAAAAAAY+/0JGcscnzdIsf+Ra31tiSv23C5lPLnSd6c+VM+AQAAwFBZRAMAAAAA9LJwyqbNLphZTCnl4CT711o/s3BoJskTy9kbAAAAdGURDQAAAAAwKjNJTi+lnJ/kn5O8I8lHR9sSAAAA02rVqBsAAAAAAKZTrfW6JH+c5NIk30ryjVrr3422KwAAAKaVnWgAAAAAgKGqte610ed/meQvR9cNAAAAzLMTDQAAAAAAAAAAU88iGgAAAAAAAAAApt7M3NzcMMcb6mAAAzSzjLc1zMfG5eybwZKZwKRY7uyRmyxGbgKTYlznmoncHCdyE5gU45qbMnO8yE1gUsjNjrYY5mAzM+33b25urrl+bm4uq1a1bbozOzubLbZo/zY9+eSTvcZevXp189jr169vrl+/fn3z/X7yySez1VZbNdUmyeOPP54tt9yyqfaJJ57IM57xjOaxH3nkkeyww5qm2gcfXJftttu+qfbhhx/Ktttu21SbJI8++mjz/X7kkUd61W699dZNtUny2GOP9fpZ9x279ff08ccfbx4Xno4+udc3c6ctN/tk5ob6acvNPpmZjC43+2RmMp252SczE7nJ8IwyN0c172rNzGQ+N0c5V+1zv/s8FrbWbqjvk11r1uzYPPa6dT/I9tvv0FT70EMPjnSu2id/+uR93591n9cG+uY9DMMocrNPZiajz81RzDf73Odk/n5vs802TbU//OEPR5qbO+20c1PtAw/c3zu7+uRPn9rWn1Uy//Ma5ditz3P6PseBYRjH9zaT/tk1rn33zc1RzDeX4/2uUcydlqPvPs9T+r5e2ed5ZZ/a1udHyfxzpD7fM7pzOicAAAAAAAAAAKaeRTQAAAAAAAAAAEw9i2gAAAAAAAAAAJh6FtEAAAAAAAAAADD1LKIBAAAAAAAAAGDqWUQDAAAAAAAAAMDUs4gGAAAAAAAAAICpZxENAAAAAAAAAABTzyIaAAAAAAAAAACmnkU0AAAAAAAAAABMPYtoAAAAAAAAAACYehbRAAAAAAAAAAAw9bbY3JWllOds7vpa67eXtx0AGF9yEwC6k5sA0J3cBIDu5CYAfWx2EU2Ss5Psl2RtkplNrptLss8gmgKAMSU3AaA7uQkA3clNAOhObgLQbKlFND+Z5OIkv1ZrvXQI/QDAOJObANCd3ASA7uQmAHQnNwFotmpzV9ZaH0ry9iS/PJx2AGB8yU0A6E5uAkB3chMAupObAPSx1E40qbVemeTKIfQCAGNPbgJAd3ITALqTmwDQndwEoNVmd6IBAAAAAAAAAIBpYBENAAAAAAAAAABTzyIaAAAAAAAAAACmnkU0AAAAAAAAAABMPYtoAAAAAAAAAACYeluMugEAAAAAAADgx5VStk9yWZJTaq13lFLekeQ3kswluSrJr9Zaf7RJzZuT/Nck9y0cOrvW+h+H2DYAjC2LaAAAAAAAAGCFKaUcleSDSfZfuLx/kt9OcniSh5OckeRdST6wSemLk/xmrfXvhtYsAEwIi2gAAAAAAABgCEopa5KsWeSqdbXWdZsce3vmF8l8bOHy40neWWt9aOG2rk/ynEVu68VJnldK+Z0k1yf59VrrD5ajfwCYdKtG3QAAAAAAAABMidOS3L7Ix2mbfmGt9dRa68UbXb6z1npukpRSdk7y7iT/sMgY9yb5wyQvTHJXkr9Y3rsAAJNrZm5ubpjjDXUwgAGaWcbbGuZj43L2zWDJTGBSLHf2yE0WIzeBSTGuc81Ebo4TuQlMirHMzVLKjum+E82GmjuSnFhrvWPh8u5JvpjkU7XW93cY77Za64492p5mchOYFGOZmxnBXHOop3OamWm/f3Nzc1m9enVT7fr163vVbrFF+7fpySefzFZbbdVU+/jjj2fbbbdtHvvRRx/NM5+5U1Pt9773QLbbbvum2ocffig77bRzU22SPPDA/dlvv9JUe8stNQcddHDz2DfccH1z/Q03XJ9Xveqnm2q/8IV/zG677d5UmyRr196TQw55YVPtddd9Iy94wSFNtd/85nU58MCDmmqT5MYbb8jee+/TVHv77bdll12e3Tz2ffd9J/vvf0BT7c0339Q8LjwdrbnZJzOT6czNPpmZTGdu9snMDfWjyM0+mZlMZ272ycxEbjI8fXJz1ar2TVpnZ2ebs69v7m255ZZNtUnyxBNPjG1u9qnt+zi8++57NNXec8/dzfmRzGdI6/OFBx64P3vuudgO/0u7665v5+CDD22qTZLrr7+21/OUww9/cVPt1Vd/Lc997l5NtUly5513ZI899myqvfvuu5rvczJ/v2EY+uTmKDN36623bqp97LHHmms31D/jGc9oqn3kkUey6667NdXee+/a5txL5rNv552f1VR7//3f7T3nO+yww5tqr7nm6hx66GFNtddee03vOV+fDOgzZ+v7POWYY36yqfbyyy9t/j1J5n9X+rwPseOOP9FU+4MffL+pbiVYWCiz6GKZLkopByQ5J8mf11r/ZJHrd0jy1lrrBxYOzSR5onW8adf3vc3W7Judne2dm61zxieeeKLXPLf17zqZ/9vuM1ft+75qn7F32GGxtXFLe/DBdb3nEH3miyeeeFJT7QUXnJ9nPWuXptok+e5378v22+/QVPvQQw9mn332bR77tttuba6/7bZbe/Xd97ldn77pzumcAAAAAAAAYIUrpWyX5MtJfnexBTQL/jnJvyulHLVw+d1JzhxGfwAwCYa6Ew0AAAAAAADQ5NQkuyR5TynlPQvHzqq1/n4p5UMLn59VSvm5JH9VStkmyc1J3jyifgFg7FhEAwAAAAAAACtUrXWvhU8/sPCx2NecutHnFyd50eA7A4DJ43ROAAAAAAAAAABMPYtoAAAAAAAAAACYehbRAAAAAAAAAAAw9SyiAQAAAAAAAABg6llEAwAAAAAAAADA1LOIBgAAAAAAAACAqbfkIppSys+UUn69lLLvJsffMbi2AGD8yEwA6E5uAkB3chMAupObAPSx2UU0pZT/kuTXk+yf5LJSyi9udPX/McjGAGCcyEwA6E5uAkB3chMAupObAPS11E40r07yylrrryd5SZL3l1LesHDdzEA7A4DxIjMBoDu5CQDdyU0A6E5uAtDLUotoZpLMJUmt9ZYkpyT5s1LKiRuOAwBJZCYAPB1yEwC6k5sA0J3cBKCXpRbRfCrJBaWUI5Ok1npDkjck+WSSfTdXCABTRmYCQHdyEwC6k5sA0J3cBKCXzS6iqbW+L8kfJnl4o2OXJjk8yd8MtDMAGCMyEwC6k5sA0J3cBIDu5CYAfW2x1BfUWs9b5NhdSU4bSEcAMKZkJgB0JzcBoDu5CQDdyU0A+ljqdE4AAAAAAAAAADDxLKIBAAAAAAAAAGDqLXk6JwAAAAAAAAAAWMlKKdsnuSzJKbXWO0opxyT5QJLtklyX5JdrrT/a3G3YiQYAAAAAAAAAgLFVSjkqySVJ9l+4vH2SzyZ5R631oIUve9tSt2MnGgAAAAAAAAAAVpRSypokaxa5al2tdd0mx96e5F1JPrZw+WVJLq+1Xrdw+dfTYY2MRTQAAAAAAAAAAKw0pyX5g0WOvy/JH258oNZ6apKUUjYcel6Sfy6lnJlk3yQXJ/mtpQa0iAYAAAAAAAAAgJXm9CRnLHJ8011oFrNFklckOTrJt5N8OMnvZJPFN4sVAQAAAAAAAADAirFwyqYuC2YW850kV9Rab0+SUsonk7x7qaJVjYMBAAAAAAAAAMBK9OUkh5dS9ly4fEqSq5cqmpmbmxtoV5sY6mAAAzSzjLc1zMfG5eybwZKZwKRY7uyRmyxGbgKTYlznmoncHCdyE5gU45qbMnO8yE1gUkxNbpZS7khyYq31jlLKq5P8UZKtk3wjyVtrrY9udsBhLqKZmZlpHmxubi6rV69uql2/fn1WrWrbdGd2djZbbNF+1qsnn3wyW221VVPt448/nh13/InmsX/wg+9np512bqp94IH7s+eez2mqveuub+eII45sqk2Sq666Mscdd0JT7cUXX9jcdzLf+8knv7yp9txzv5xDDnlhU+11132juXZD/bHHvqSp9rLLLsnrX//GptpPf/oTOemkk5tqk+T888/NG97w8021n/rU3zf3ncz3XsqBTbW13phMUdAwMnMzM20/rj6ZmUxnbvbJzGQ6c7NPZiajy80+mZlMZ272ycwkqfVGi2gYhrHNzT7z3K233rqpNkkee+yxXrn5zGfu1Dz29773QHbddbem2nvvXZsDDnh+U+1NN30rL3nJ8U21SXLJJRdln332baq97bZbc/jhL24e++qrv5aDDz60qfb666/tVXvooYc11SbJtddek9e85nVNtWeddWZ+6qdOaar94hc/nze+8U1NtUnyiU/8bX7u536hqfaTn/y77L//Ac1j33zzTeM610zk5jjplZt9cq+1dkN9n9xsnWsm8/PN7bbbvqn24Ycfym677d5Uu3btPTnwwIOaapPkxhtvyItedERT7de/flX22680j33LLTW77PLsptr77vtOjj/+xKbaiy66IIcddnhTbZJcc83VOfLIo5tqr7zyirz0pS9rqj3vvK/kF3/xl5tqk+TjH/9or777jn3KKT/TVPv5z/9Dr9e14zVahqDve5t9crM1r5dj7C233LKp9oknnuiduWvW7NhUu27dD7LDDmuax37wwXXNr9NeddWVvfK+NTOT+dxszexbbqnN85ebb76p9/OUPtnV97XpPq8t9Hk9/phjfrKpNkkuv/zSXvP7yM3OnM4JAAAAAAAAAICpZxENAAAAAAAAAABTzyIaAAAAAAAAAACmnkU0AAAAAAAAAABMPYtoAAAAAAAAAACYehbRAAAAAAAAAAAw9SyiAQAAAAAAAABg6llEAwAAAAAAAADA1LOIBgAAAAAAAACAqbfFUl9QStkvySO11rWllFOT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V1xxWV73utc31Z555qdzzDE/2VR7+eWX5mUve0VTbZJ85Stfyqte9dNNtV/4wj/msMMObx77mmuuzoEHHtRUe+ONNzSPC09Hn9zrm7nTlpt9MjOZztzsk5nJ6HKzT2Ym05mbfTIzkZsMT5/cXLWqfZPW2dnZ7LDDmqbaBx9cl513flZT7f33fzc77bRzU22SPPDA/TnooIObam+44focccSRzWNfddWVeclLjm+qveSSi3LSSSc31Z5//rnZd9/nNdUmya23/lOOP/7EptqLLrogL3rREc1jf/3rV+XlL39lU+2Xv3xOTjzxpKbaCy44P6997b9pqk2Sz33uMzn88Bc31V599ddywgn/uqn2wgv/V4488uim2iS58sor8oIXHNJU+81vXpcDDnh+89g33fSt5lp4Okb1OuvWW2/dVJskjz32WHbZ5dlNtffd953muWYyP9/s87jQp/b1r39jU22SfPrTn+j1WNr38extb3tHU+2HP/zXveZ8v/mbv91UmyR/+qf/V97ylrc11Z5xxofzmte8rqn2rLPObM7rZD6zW39XPv3pT+RXfuXU5rH/5m8+1Ot3fM89n9NUe9dd326qg6er7+usrfPN2dnZbLXVVs1jP/74481zxgceuD+7775HU+0999zdXLuhvpQDm2prvbF3dh188KFNtddff2322mvvpto77ri99+vDfXKzzxz7kENe2FSbJNdd941eP+vW2g31fZ4jvfrVr2mqPfvss7LffqWpNkluuaVm1113a6q99961zeNOo6EuogHgxw15RzAAGGtyEwC6kZkA0J3cBIDuJj032//dDgAAAAAAAAAAJoSdaABGbNJXawLAcpKbANCNzASA7uQmAHQ36blpJxoAAAAAAAAAAKaenWgARmzSV2sCwHKSmwDQjcwEgO7kJgB0N+m5aScaAAAAAAAAAACmnp1oAEZsdnZ21C0AwNiQmwDQjcwEgO7kJgB0N+m5aScaAAAAAAAAAACmnp1oAEZs0s8bCADLSW4CQDcyEwC6k5sA0N2k56adaAAAAAAAAAAAmHpL7kRTSnlFkq/WWteVUt6c5MgkV9da/2bg3QFMgUlfrTlNZCbA4MnNySE3AQZLZk4WuQkwWHJzsshNgMGa9Nzc7E40pZTTk7w3ydallPcn+d+T3JDkdaWUPxtCfwAwFmQmAHQnNwGgO7kJAN3J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aCYAdKebANDd2Lu5asLv4Lg/msAsWbVUb+gd77huYl8br7rqB5ds3QxOM4GxWNL26CaPQjeBsViR55qJbq4wugmMxYrspmauOLoJjIVudjTRnWhWrWp//+bn57NmzZqm2f379+fkk9c3zT7wwM6cf/4FTbNJctddd2bDhtObZrdt25oTTzyp+di7d+/KCSec0DT74IMP5pRTHtc0u2PHt3LOOec2zSbJvffek0suubRp9qtfvTlnnXV287E3b96USy+9vGn25ptvyrnnntc0e889dzd/vJOFj/mpp57WNHv//dubP892796VtWvXNs0myd69e5vn9+7dm9NO29B87O3bt/X6+1pKc3NzS/r2GI/WbvZpZjKb3ezTzGQ2u9mnmcn0utmnmclsdrNPMxPdZHKm2c2TTjq5aXbXrgeau9mnmclCN/ucL06zmxde+MSm2dtv/3rOSTNhHwAAIABJREFUOOPxTbNJsmXLN7N+/SlNszt37sjFFz+p+di33npLr2b3OV9sfZ+Thfe7TzePP/74ptl9+/b1/hzt081Sntx87Fq/1jx7OM3kaPp089hj255Sfvjhh5vPNZOF880+DejbzT7fi69bt65pds+ePb3X3ee8q++50+mnn9E0u3XrlmzceGHT7B133J4zzzyraTZJ7rtvc6/nRPr0o2+7+nxv1/fnEH3e7+/8zsuaZv/8z7/SNPdodJNH0/dnm8ccc0zT7COPPNLcj6RfQ7Zt2zqVnzkl/X+22fe5tz5fz/q0q+/3SK3tu+++zb3e576fo32+R2o9X0wWzhmPO+64ptmHHnqo1/eF0/y7Xkpj7+bqaS8AAAAAAAAAAACmbaI70QDw7cZ+30AAWEq6CQDdaCYAdKebANDd2LtpJxoAAAAAAAAAAGaenWgApmzsV2sCwFLSTQDoRjMBoDvdBIDuxt5NO9EAAAAAAAAAADDz7EQDMGVjv1oTAJaSbgJAN5oJAN3pJgB0N/Zu2okGAAAAAAAAAICZZycagCkb+9WaALCUdBMAutFMAOhONwGgu7F30040AAAAAAAAAADMPBfRAAAAAAAAAAAw89zOCWDK5ubmpr0EAFgxdBMAutFMAOhONwGgu7F30040AAAAAAAAAADMvEV3oimlfF+SlyU5J8lcks1JPlJrfd/AawOYCfPz89NeAktINwGGpZvjopsAw9HM8dFN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\n", 282 | "text/plain": [ 283 | "
" 284 | ] 285 | }, 286 | "metadata": { 287 | "needs_background": "light" 288 | }, 289 | "output_type": "display_data" 290 | }, 291 | { 292 | "data": { 293 | "text/plain": [ 294 | "
" 295 | ] 296 | }, 297 | "metadata": {}, 298 | "output_type": "display_data" 299 | }, 300 | { 301 | "data": { 302 | "text/plain": [ 303 | "
" 304 | ] 305 | }, 306 | "metadata": {}, 307 | "output_type": "display_data" 308 | }, 309 | { 310 | "data": { 311 | "text/plain": [ 312 | "
" 313 | ] 314 | }, 315 | "metadata": {}, 316 | "output_type": "display_data" 317 | }, 318 | { 319 | "data": { 320 | "text/plain": [ 321 | "
" 322 | ] 323 | }, 324 | "metadata": {}, 325 | "output_type": "display_data" 326 | }, 327 | { 328 | "data": { 329 | "text/plain": [ 330 | "
" 331 | ] 332 | }, 333 | "metadata": {}, 334 | "output_type": "display_data" 335 | } 336 | ], 337 | "source": [ 338 | "# different windows sizes for sentiment score b\n", 339 | "#h = 24\n", 340 | "s_days = 20 # short\n", 341 | "l_days = 20 # long\n", 342 | "\n", 343 | "f, axes = plt.subplots(1, 5, figsize=(40,10))\n", 344 | "win_all_a = np.zeros(shape=(s_days,l_days))\n", 345 | "# matrix of size (s_days,l_days)\n", 346 | "for std in range(0,5):\n", 347 | " for i in range(0, s_days):\n", 348 | " for j in range(0, l_days):\n", 349 | " sent_score_a = ah.nb_calc_sentiment_score_a(aug_signal_a,aug_signal_b,(i+1)*24+np.random.uniform(0,std),(j+1)*24+np.random.uniform(0,std))\n", 350 | " win_all_a[i,j] = ah.nb_backtest_a(price_data, sent_score_a, 1.0, 0.0075)[-1]\n", 351 | " cmap = sns.cubehelix_palette(50, hue=0.05, rot=0, light=0.0, dark=1.2, as_cmap=True)\n", 352 | " figure(num=None, figsize=(10, 7), dpi=80, facecolor='w', edgecolor='k')\n", 353 | " ax = sns.heatmap(win_all_a, linewidth=0.01, cmap=cmap,ax=axes[std])\n", 354 | "plt.show()\n" 355 | ] 356 | }, 357 | { 358 | "cell_type": "code", 359 | "execution_count": 14, 360 | "metadata": {}, 361 | "outputs": [ 362 | { 363 | "data": { 364 | "image/png": "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3nhjjfLThAEAgFopPT1dS5YsOeNjkyZN0uTJk2scKzc3V/fff7+aNWumadOm1ejP0IQBAICAZ2ISdtttt2nAgAFnfCwqKqrGcTZt2qRJkyYpISFBycnJCgqq2dleNGEAAKBWio6O/sWS49naunWrxowZozlz5uimm246qz9LEwYAAAJeoO6otXjxYnk8Hi1btkzLli2run/FihVe/6zXJmz//v264AKzX0EGAACojsfj8XcJVX5+rtizzz57znG8LloOHjxYL7744jknAAAAwC95bcJiY2P18ccfa8yYMdqzZ48vagIAADhNIOwTZjevTVhYWJhefPFF9e7dW6NGjVJycrK+/PJLnThxwhf1AQAAOFKNvkMZFBSksWPHas2aNerSpYv+9re/6fLLL1f//v0NlwcAAODMSZjXE/N/XmSjRo00duxYjR07VseOHVNmZqbJ2gAAACQF7rcjz4fXSdjo0aPPeH9YWJguueQS2wsCAACoDbxOwkaOHOmLOgAAAH5VrZyEAQAAwH7smA8AAAJeIG3WaheaMAAAEPBYjgQAAIAtmIQBAICA58BBmFyWE+d7AADAUT744CPbY1533bW2xzwbfpmEuVwuo/Ety/JJjiZNwo3FLyoqVGhoqLH4klRSUqIWLVoazZGdfdAnz6Np02ZGcxQUHDGao6DgiBo0aGAsviSVlpYqNraV0RxZWQeMHhfSyWOjceMmRnMUFxepTZu2xuL/9FOmT469mJjmRnPk5Bzyyfvti98hJnOUlJSoUaPGxuJL0tGjxT75HeJPTpwZsRwJAAACnhObME7MBwAA8AMmYQAAIOA5cZ8wJmEAAAB+wCQMAAAEPCeeE0YTBgAAAp4Tm7CzWo4sKyvT1q1bVVJSYqoeAACAWqHaSdju3bv16KOPqkGDBpo6daruvfdeud1uud1uPfvss+rWrZuv6gQAALVYrZuEPfrooxo8eLAuv/xy3XXXXZo6darWrl2rRYsW6fHHH/dVjQAAAI5T7STs2LFjuuOOOyRJr732moYMGSJJuuKKK/y+cy4AAKg9nDgJq7YJc7vd2rNnj4qKinT48GH99NNPatOmjXJycnTixAlf1QgAAGo5J+4TVm0Tdv/992vYsGEKCgrSY489pqSkJHXr1k0bNmzQxIkTfVUjAACA41TbhA0cOFDffPON3G63QkND1blzZ61du1a3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wOu1I/3piy++0F//+leVl5erRYsWWrBggaKjo43keuqpp5SXl6e5c+faGve1117T//7v/8rlcqlBgwaaMWOG4uPjbc0hSW+++aZefPFFSVLTpk01e/ZstWvXzvY8mzZt0ujRo7VmzRo1b97c1tjTp0/X119/rUaNGkmS2rRpo0WLFtma48cff9ScOXN09OhRBQUFadasWerevbtt8d944w298sorVT8fP35cBw4c0OrVq9WmTRtbcqxZs0ZPP/20goKCFBYWpjlz5qhDhw62xD7ltdde00svvaSQkBC1bNlSjz76qG3v938faytWrNCyZctUWVmpzp0767HHHlNYWJitOSTJ4/Fo+vTpatOmje67777zin+mHEuWLNF7772noKAgRURE6JFHHjnvY/C/cyxbtkz//ve/5XK51Lp1a6WmpioyMtLWHKd8+OGH+p//+R9t2bLF1vh33XWXcnJyVL9+fUnSFVdcoZkzZ9qaY/369Vq4cKHKysrUsGFDzZs3z9b3YsmSJfrwww+rHissLFRBQYHWrVun0NBQ257Hv/71L7300ksKDg5W8+bNNXfu3PP+O/DnOSzL0pIlS/TOO++obt266tSpk1JSUtS4cePzyoGzYAWow4cPW1deeaW1Y8cOy7IsKy0tzRozZoztefbv32/dd999Vnx8vPXnP//Z1tgbNmyw+vfvbx0+fNiyLMv6+OOPrd69e1sej8fWPLt377auuuoqKz8/37Isy3rppZesO+64w9YclmVZ+fn5VkJCgnXRRRdZ2dnZtscfNGiQtXPnTtvjnlJaWmr16dPHWr16tWVZlvXJJ59Y/fv3t/39OKWystK64447rH/+85+2xSwtLbW6du1q/fjjj5ZlnXyvR48ebVt8y7KsdevWWb1797aysrIsy7Kst99+2xo5cuR5xz3TsbZr1y7rqquusg4dOmRZlmXNnz/fSklJsTWHZVnW9u3brcTERCs+Pt76+9//bvvzWLlypTV8+HDr+PHjlmVZ1ssvv2zdcssttub44osvrBtuuKEqx7x586yHHnrI1hynZGRkWAMGDLA6d+5sa/wTJ05Yl156qVVUVHTOcb3lOHTokHXFFVdY33//vWVZlvXKK69YiYmJtub4uaNHj1o33nij9e6779qaY9++fdZll11m5eXlWZZ18tiYNm2arTneeust66abbrIKCwsty7KsJUuWWFOmTDnnHDh7AbscuXbtWsXFxSkuLk6SdPvtt+vrr79WXl6erXnS09N19dVXKykpyda4ktSkSROlpqaqWbNmkqT4+HgdPnxYpaWltuZp3769PvvsM0VERKiyslIHDx5U06ZNbc1RWVmp5ORkTZ061da4p+Tn5+vgwYNatGiRbr75Zk2ePFlZWVm25li7dq2ioqJ03XXXSZL69eunZ555Rpahy6e++OKLCg4O1pgxY2yL6Xa75XK5VFRUJEkqKSmpmijYZcuWLbryyivVsmVLSdJ1112nTZs2nff7caZjbc2aNerXr59iYmIkSaNHj9aqVavk8XhsyyFJL7/8skaNGqUbbrjh3J9ANTnatGmjmTNnVk1B4uPjz+v1OlOOPn36aMWKFQoNDVV5ebny8vLO6zj/tdfq2LFjmjp1qmbMmHHOsX8t/rZt21S3bl396U9/0s0336zp06eroKDA1hzvv/++evXqpW7dukmSRo4cqdmzZ9ua4+eeeOIJdevW7bw+W2fK4fF45Ha7VVJSIsuyzvtYP1OOH374Qddcc42aNGki6eSx/uGHH+rEiRPnnAdnJ2CbsEOHDqlFixZVP9etW1dNmzZVdna2rXkefPBBjR49WsHBwbbGlaQOHTqoT58+kk4eUPPmzVP//v3Pa1z9a0JCQrR+/Xr169dP6enptjeVCxcuVM+ePdW7d29b456Sm5urPn36aPr06Vq5cqXi4+M1YcIEud1u23Ls3btX0dHRmjlzpoYPH667775bJ06cUFCQ/YdBcXGxli5dqpkzZ8rlctkWt2HDhpo9e7buvvtu9e3bV88//7ztjXF8fLy++eYb7d+/X5L073//W9LJ9+h8nOlYy87OPu04b968uUpKSlRYWGhbDkmaO3euhgwZcm6F1yBHfHy8Lr30UklSeXm5/vKXv+jGG2+0NYd08jh/55131LdvX3377be67bbbbM8xffp03X333brooovOOfavxS8qKlKvXr20YMECvf322woNDT2vz++Zcuzdu1cNGzZUcnKyhg0bpsmTJ5/X7/fq/o7IzMzUqlWr9Kc//emc4/9ajjZt2mjChAm68cYb1adPH61du/a8ltF/7XP76aef6siRI7IsSytXrlRFRcU5H384ewHbhFmWdca/vEz8hWnasWPHNGnSJGVlZWnBggXG8vTo0UNffvmlFi5cqPHjx6u4uNiWuO+884727dunP/7xj7bEO5OLL75Yzz77rGJjY+VyuXTvvfcqKytLmZmZtuWorKzUl19+qaFDh+qtt97S2LFjNX78eB07dsy2HKe8/vrruvrqq3XhhRfaGnfnzp1atGiRVq5cqc8//1wzZ87UuHHjVFJSYluOK664Qg888IDuv/9+jRgxQiUlJQoPD1dISIhtOX7uTMe5nY2rL+Xm5uruu+9Wo0aNNG3aNCM5hgwZoq+//lrjx4/X2LFjz3lqeCZLly5VZGSkEhISbIv5c3379tVTTz2lpk2bqk6dOpo0aZLWrl1r6+e3srJSn3zyiSZOnKi3335b11xzjSZMmGBb/J9LS0vTrbfeWrXaYae1a9fqnXfe0UcffaS1a9fq9ttv14QJE2yd3A8dOlRDhgzR3Xffrdtvv73qvE9Txzp+KWA7mpYtWyonJ6fq5xMnTqigoKBqieS3Yu/evbrlllsUFhamtLQ0Iyc8HjhwQP/5z3+qfh44cKBCQkK0b98+W+K/+eab2rdvn4YOHVr1y3ns2LFav369LfElaePGjXr//fdPu8+yLNWpY993R2JiYtS2bVv16NFD0snlyDp16mjPnj225Tjl3Xff1YgRI2yPu3btWnXt2lXt27eXJN18881yu93avXu3bTmOHz+uHj166O2339abb76pESNG6OjRo2rdurVtOU757+M8JydHDRs2rFoe+S3ZtGmTRowYoR49emjJkiWqW7eurfF//PFHbdq0qernkSNH6sCBA1VL03Z4++23tX79eiUkJGj8+PFyu91KSEiw7XfJZ599pi+//LLqZ8uyFBQUZPtx3r1796ovqwwfPlyZmZk6cuSIbTmkk6sb7733npHjXJI+/vhj9e3bVzExMXK5XLrrrru0bdu281q+/W+FhYW66aabtGrVKqWnp6tbt24KDw9XeHi4bTlQvYBtwnr37q1t27Zp165dkk5+66xbt25G/sVhysGDBzV69GiNHDlSCxcuVL169YzkKSoq0pQpU3To0CFJJ3/RBQUF2faNuRdeeEHvvvuuVqxYoRUrVkiSli9fXtXM2OHEiRNKTU2tWvJ6+eWX1aFDB1v/4u/bt6+ys7P1/fffS5I2bNigEydOVDU0djl69Kh27dqlK664wta4ktSlSxdt2LCh6r3+9ttvVVlZaes3YXNzczV69Oiqv9z/8Y9/aMCAAUb+AXHttdfqs88+q2rEXn31VQ0cOPA3N/HeunWrxowZo4cfflh/+tOfjNSfmZmpqVOn6ujRo5Kkt956S3Fxcbae//n+++9r1apVVd9YDQ4O1ooVK2w7Do8cOaJ58+ZVTZ+XLVumgQMH2tqwDho0SBs3bqyaon/wwQdq3bq17Y3Frl27VLduXdt/f5zSpUsXffHFF1Xv96lvWNv5d+C2bdv0hz/8QSdOnJDb7dbSpUs1dOjQ3+wk+rcoYLeoaNasmZ588kk99NBDKi8vV0REhBYuXOjvss7K8uXLVVxcrJUrV2rlypVV9y9btqzqRGQ7dOnSRQ899JDGjRunoKAgNW7cWM8995waNGhgWw7Tevbsqfvuu09JSUlyu91q2bKlnn76aVt/GURGRmrp0qWaN2+eSkpKFBwcrMWLF5/3dgj/LTMzU82aNbP9hHlJ6tWrlyZOnKikpCSFhIQoNDRUzzzzjK3PoV27dpo8ebJGjRolt9utiy++WPPmzbMt/s917NhR06ZN07333quKigq1a9dOjz/+uJFcJi1evFgej0fLli3TsmXLqu4/9Y8WOwwaNEh79+7Vbbfdpjp16qhFixb6+9//blt8Xxg2bJj27dunkSNHyuPxKC4uTnPmzLE1R6dOnTR37lw98MADqqysVFhYmBYvXmx7Y5yZmanY2FhbY/7c8OHDlZ2drVtuuUX16tVTs2bN9Mwzz9ia4+qrr9bgwYM1dOhQVVRUqE+fPnrwwQdtzYHquSxTXw0DAADAr/ptzfwBAAAcgiYMAADAD2jCAAAA/IAmDAAAwA9owgAAAPyAJgwAAMAPaMIAAAD8gCYMAADAD2jCAAAA/OD/As7goqgI680lAAAAAElFTkSuQmCC\n", 365 | "text/plain": [ 366 | "
" 367 | ] 368 | }, 369 | "metadata": {}, 370 | "output_type": "display_data" 371 | } 372 | ], 373 | "source": [ 374 | "cmap = sns.cubehelix_palette(50, hue=0.05, rot=0, light=0.0, dark=1.2, as_cmap=True)\n", 375 | "figure(num=None, figsize=(10, 7), dpi=80, facecolor='w', edgecolor='k')\n", 376 | "ax = sns.heatmap(win_all_a, linewidth=0.01, cmap=cmap)\n", 377 | "plt.show()" 378 | ] 379 | }, 380 | { 381 | "cell_type": "code", 382 | "execution_count": 15, 383 | "metadata": {}, 384 | "outputs": [], 385 | "source": [ 386 | "# different windows sizes for sentiment score b\n", 387 | "#h = 24\n", 388 | "s_days = 20 # short\n", 389 | "l_days = 20 # long\n", 390 | "\n", 391 | "win_all_b = np.zeros(shape=(s_days,l_days))\n", 392 | "\n", 393 | "# matrix of size (s_days,l_days)\n", 394 | "\n", 395 | "for i in range(0, s_days):\n", 396 | " for j in range(0, l_days):\n", 397 | " sent_score_a = ah.nb_calc_sentiment_score_a(aug_signal_a,aug_signal_b,(i+1)*24+np.random.normal(0,1),(j+1)*24+np.random.normal(0,1))\n", 398 | " win_all_b[i,j] = ah.nb_backtest_a(price_data, sent_score_a, 1.0, 0.0075)[-1]\n" 399 | ] 400 | }, 401 | { 402 | "cell_type": "code", 403 | "execution_count": 16, 404 | "metadata": {}, 405 | "outputs": [ 406 | { 407 | "data": { 408 | "image/png": "iVBORw0KGgoAAAANSUhEUgAAAmsAAAHLCAYAAACXuN+XAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAMTQAADE0B0s6tTgAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4xLjAsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy+17YcXAAAgAElEQVR4nOzde3zP9f//8ft7B4c524nNWU7JJEQISaXwGUrYdJhTPqL2WR/6+DCphfh8O6FCKdNx9SuhE+lIZ5IIsViY2cFhDmNse/3+8LFPy9p78Xq+91rv2/Vy2eXi/X7P4/F4bXvPw+P5ej1fLsuyLAEAAMCRfMq6AAAAAPwxmjUAAAAHo1kDAABwMJo1AAAAB6NZAwAAcDCaNQAAAAejWQMAAHAwv7JI6nK5jMa3LKvc5/grHAM5nBOfHM7K8Vc4hnM5fHzM/p+/oKCg3H+t/krfb5QNJmsAAAAORrMGAADgYDRrAAAADkazBgAA4GA0awAAAA5GswYAAOBgpdq64+DBg0pLS5OPj4/q1q2rWrVqma4LAAAActOsZWVl6V//+pe+/vpr1a5dW5J0+PBhXX755ZozZ47q1q3rkSIBAAC8lcsqYZe7kSNHqmfPnho6dKj8/f0lSWfOnNHrr7+uVatWaenSpReW9C+yOSCbKJKjvMQnh7Ny/BWO4VwONsUt+/iezIGyUeK7LC0tTbfddlthoyZJ/v7+io6O1qFDh4wXBwAA4O1KbNYqVKig5OTk855PTk5WhQoVjBUFAACAs0o8Z+2+++5TdHS0WrVqVXh+Wnp6urZt26bHHnvMIwUCAAB4sxLPWZOkQ4cO6YsvvlBaWpokKSwsTF27dr2oK0L/Kmv3nONAjvISnxzOyvFXOIZzOThnrezjezIHyobbZs1I0r/IDy1vbnKUl/jkcFaOv8IxnMtBs1b28T2ZA2WDTXEBAAAcjGYNAADAwWjWAAAAHIxmDQAAwMFo1gAAABysTK4GBQAAQOmUuCmuKX+VS5hNXrJeUFAgX19fY/ElKT8/3yOX3Xsihye+Vn5+5t4ueXl5RuOfy/HbW8eZcObMGVWuXNlojpMnT6pGjZpGc2RnH1GtWrWNxT98+JACAgKMxZeknJwcValSxWiOEydOqFq16kZzHDt21CM/t9Wr1zAW/+jRbFWqVMlYfEk6deqUR3KgbLAMCgAA4GA0awAAAA5GswYAAOBgNGsAAAAORrMGAADgYDRrAAAADkazBgAA4GA0awAAAA5GswYAAOBgNGsAAAAO5vb+NvHx8SW+npCQYFsxAAAAKMptsxYYGKjExETFxMQYv8cjAAAAinLbrMXGxio5OVlBQUGKioryRE0AAAD4r1KNyiZPnqwDBw6YrgUAAAC/U6pmLTw8XHFxcaZrAQAAwO9wEhoAAICD0awBAAA4GM0aAACAg9GsAQAAOJjLsiyrrIsAAABA8dzus2aCy+UyGt+yLOMb+BYUFMjX19dY/Pz8fPn5mf325OXlqWLFikZz5ObmKjS0jtEc6ekH1LhxE6M5du/epWrVqhuLf+zYUdWsWctYfEk6cuSwGjZsZDTHr7+m6LLLIozm2LLlR8XEjDKa44UXnlNwcIix+JmZGQoLCzcWX5L270/VFVd0MJrj++/Xe+T77Ymf22bNWhiLv3Pnz3+Z7zfKBsugAAAADkazBgAA4GA0awAAAA5GswYAAOBgNGsAAAAORrMGAADgYDRrAAAADlaqZu3UqVPnPZeZmWl7MQAAACiqxGbtxx9/VLdu3dS+fXuNHz9ex48fL3xtzJgxxosDAADwdiU2azNnztTDDz+szz//XBUrVtTo0aN15swZSWfvEgAAAACzSmzWTp06pZ49eyowMFD/93//p1q1amnatGmeqg0AAMDrldis5efnKzs7W9LZ+3nOmTNHP/zwg1544QXj9/cEAACAm2YtKipKAwcO1JdffilJqlq1qp5++mk999xzSk5O9kiBAAAA3syvpBeHDRumli1bqnr16oXPNW7cWG+88Yaef/5548UBAAB4uxKbNUlq167dec+FhYVp6tSpRgoCAABwsieeeEKZmZmaMWOGJGn+/Pl6//335ePjo8DAQD3wwANq3LjxeX9v/vz5eu211xQYGChJqly5sl577TW3+dw2awAAAJD27dunWbNmad26derXr58kaeXKlfrkk0/0xhtvKCAgQC+99JImTZqkN95447y/v2HDBiUkJOiaa675U3m5gwEAAEApJCUlqUuXLoqJiSl8rmHDhpo6daoCAgIkSREREUpNTT3v7+bn5+uHH37QG2+8ocjISI0cOVLbt28vVV4mawAAwCtlZGT84R2ZgoODFRISUuS5++67T5I0b968wuciIiIK/5ybm6v//Oc/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JmsAAMBjCgoKbP8oL0ps1rKzs5WcnKxGjRrpwIEDhc9nZWUZv50TAADAOSyD/oFOnTrp7rvv1scff6wHH3xQkrRq1SoNGDBA0dHRHikQAADAm5W4dcesWbMkSQcPHlRGRoYkKTQ0VI899piuvNLsDcABAADOKU+TMLuVap+1wMBABQYGSpIuv/xyowUBAADgf9gUFwAAOJ4XD9Zo1gAAgPN58zIol3QCAAA4GJM1AADgeOVpXzS7MVkDAABwMJflzYvAAACgXNi+fYftMVu2bG57TBPKZBnU5XIZjW9ZlvE7LBQUFMjf399Y/DNnzqhevfrG4kvSvn17FR5ez2iO1NR96tDB7J5869d/q/btOxrNsWHDd7r22uuMxf/oow8VFzfRWHxJeuyx/6hbt+5Gc6xb97l6977eaI41a1Zr8OChRnO88cZruu66G4zF//DDVercuYux+JL09ddfGj0G6exxeOJnasSI0UZzPP/8s/rb3wYai79ixTJdcUUHY/El6fvv16tNm7ZGc2zevMlofHe8ebbEMigAAICD0awBAADHc9K9QZ944glNmTKl8PHy5cvVt29f3XDDDYqNjdXx48eL/Xt79+7Vbbfdpr59+6p///7auHFjqfLRrAEAAJTCvn37dPfdd+uFF14ofG7nzp2aPXu2nn/+ea1atUp16tTRnDlziv37cXFx6tevn959913NmjVLEyZMUE5Ojtu8NGsAAMDxnDBZS0pKUpcuXRQTE1P43Jo1a9SjRw+FhoZKkqKjo7Vy5crzthpJT0/X9u3bNWjQIEnSZZddpkaNGunTTz91m5d91gAAgOOZ2GctIyNDmZmZxb4WHByskJCQIs/dd999kqR58+YVPpeWlqa6desWPq5Tp45ycnJ05MgR1a5du8jnBQUFFbk4MTQ0VPv373dbJ80aAADwSklJSZo/f36xr40fP14TJkwoVZzidrn4/XOWZRX7eaXZveJPNWs5OTnatWuXmjRpooCAgD/zVwEAAC6Yia07hgwZol69ehX7WnBwcKlihIWFad++fYWP09PTVaVKFdWoUeO8z8vKylJeXp78/M62XxkZGerdu7fbHCU2a5s2bdI//vEPPfPMM8rNzdVdd90lX19fnTlzRk899ZQ6dDC7bwwAAIApISEh5y11/lnXXnutRowYofT0dIWGhurll19W7969z5uYhYaG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HvBUjQAAwMtZlmX7R3lRYrOWlpamyMhIVa5cWVFRUXr//fdVs2ZNTZkyRT/99JOnagQAAPBaJS6Dnj59Wunp6QoNDVVqaqry8/MlSUePHjV6X0wAAIDfKutJ2BtvvKGXXnqp8PGJEye0b98+rVq1Sg0bNix8/u2339asWbNUp87/7pv74osvqnr16hecu8Rm7bbbbtMtt9yiK6+8Ut99953uvfdepaSkKDo6Wvfcc88FJwUAAPgzyrpZGzx4sAYPHixJys/P15133qlhw4YVadQkaf369ZowYYKGDx9uW+4Sm7Vhw4apSZMm+umnnzRs2DB16NBBOTk5evnll9WoUSPbigAAAPC0jIwMZWZmFvtacHCwQkJCin1tyZIl8vX11YgRI857bcOGDUpLS9Nbb72lSpUqKTY2VldeeeVF1el2645OnTqpU6dOhY8DAgJo1AAAgEeZ2GctKSlJ8+fPL/a18ePHa8KECec9f/ToUS1cuFCvvPKKXC5XkddOnz6tsLAwjRw5Ul26dNF3332ncePG6a233lL9+vUvuE42xQUAAF5pyJAh6tWrV7GvBQcHF/v866+/ri5duuiSSy4577UKFSpo8eLFhY87duyo9u3ba+3atYqKirrgOmnWAACA45k4Zy0kJOQPlzr/yHvvvad//OMfxb6Wnp6ud999t8jyqGVZ8vf3v6g6uTcoAABwPCfss3bs2DHt2LFDHTt2LPb1gIAAPf300/rqq68kSZs3b9YPP/yga6655qKOnckaAABAKaSkpKh27dqqVKlS4XPp6ekaM2aMFi1apNDQUD311FOaM2eOcnNz5efnpyeeeEJBQUEXlZdmDQAAOF5Zb90hSW3atNHnn39e5LnQ0FAtX7688HGnTp305ptv2prXZTnh6AEAAErw7LPP2x5z9Ojzt95wojKZrP3+Ule7WZalihUrGs2Rm5trNEdubq7q1bvwy3xLY9++vapfv4HRHHv37lG1ahe+a3NpHDt21CPf7+DgP3cS6p+RmZnhke9F06bnX71kp19+SfbIcbRq1dpojm3bflJoaB33n3iB0tMPKCio+CvN7JKVlam6dcOM5khL22/06ySd/Vr9dsnJhFOnThn9PXXs2FGPfJ088d4rSya27igvWAYFAACO580LgVwNCgAA4GBM1gAAgON582SNZg0AADieNzdrLIMCAAA4GJM1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nTqaMWPGRf8b+NsclmVp/vz5euedd1ShQgW1bNlS8fHxql69+kXlgAGWQx08eNC68sorre3bt1uWZVmJiYnWiBEjbM+zd+9ea9y4cVZERIT173//29bYGzZssHr27GkdPHjQsizL+vjjj62uXbtaBQUFtub55ZdfrKuuusrKysqyLMuyli5dag0fPtzWHJZlWVlZWVZkZKTVvHlzKy0tzfb41113nfXzzz/bHveckydPWt26dbNWrVplWZZlffLJJ1bPnj1t/36ck5eXZw0fPtx67rnnbIt58uRJq02bNtbOnTstyzr7vY6OjrYtvmVZ1tdff2117drVSk1NtSzLspYtW2YNHjz4ouMW917bsWOHddVVV1kHDhywLMuyZs2aZcXHx9uaw7Isa9u2bVZUVJQVERFhPfXUU7Yfx4oVK6xBgwZZJ06csCzLsl588UXrlltusTXH2rVrrRtvvLEwx8yZM63777/f1hznJCcnW7169bJatWpla/zTp09b7dq1s7Kzsy84rrscBw4csDp27Gj98MMPlmVZ1ksvvWRFRUXZmuO3jh07Zt10003We++9Z2uOPXv2WFdccYWVmZlpWdbZ98akSZNszfHWW29Zffv2tY4cOWJZlmXNnz/fio2NveAcMMexy6Dr1q1TixYt1KJFC0nS0KFD9c033ygzM9PWPElJSerSpYtiYmJsjStJNWrUUEJCgmrXri1JioiI0MGDB3Xy5Elb8zRp0kSfffaZAgMDlZeXp/3796tWrVq25sjLy1NcXJwmTpxoa9xzsrKytH//fs2dO1f9+/fXhAkTlJqaamuOdevWKTg4WNdff70kqUePHnrmmWdkGbo97pIlS+Tr66sRI0bYFjM/P18ul0vZ2dmSpJycnMIJhV22bNmiK6+8UmFhYZKk66+/Xps2bbro70dx77U1a9aoR48eCg0NlSRFR0dr5cqVKigosC2HJL344osaNmyYbrzxxgs/gBJyNGzYUFOnTi2cqkRERFzU16u4HN26ddPy5csVEBCg3NxcZWZmXtT7/I++VsePH9fEiRM1ZcqUC479R/G3bt2qChUq6J///Kf69++vyZMn6/Dhw7bm+OCDD9S5c2e1bdtWkjR48GA9+OCDtub4rccee0xt27a9qJ+t4nIUFBQoPz9fOTk5sizrot/rxeXYvHmzrrnmGtWoUUPS2ff6hx9+qNOnT19wHpjh2GbtwIEDqlu3buHjChUqqFatWkpLS7M1z3333afo6Gj5+vraGleSmjZtqm7dukk6+8abOXOmevbseVFj8j/i7++v9evXq0ePHkpKSrK9+ZwzZ446deqkrl272hr3nIyMDHXr1k2TJ0/WihUrFBERobFjxyo/P9+2HLt371ZISIimTp2qQYMG6Y477tDp06fl42P/2+Do0aNauHChpk6dKpfLZVvcKlWq6MEHH9Qdd9yh7t276/nnn7e9gY6IiNC3336rvXv3SpLefvttSWe/RxejuPdaWlpakfd5nTp1lJOToyNHjtiWQ5JmzJihfv36XVjhpcgRERGhdu3aSZJyc3P1n//8RzfddJOtOaSz7/N33nlH3bt313fffachQ4bYnmPy5Mm644471Lx58wuO/Ufxs7Oz1blzZ82ePVvLli1TQEDARf38Fpdj9+7dqlKliuLi4jRw4EBNmDDhon6/l/RvREpKilauXKl//vOfFxz/j3I0bNhQY8eO1U033aRu3bpp3bp1F7V8/0c/t59++qkOHToky7K0YsUKnTlz5oLffzDHsc2aZVnF/iNn4h9W044fP67x48crNTVVs2fPNpanQ4cO+uKLLzRnzhyNGTNGR48etSXuO++8oz179ujvf/+7LfGKc+mll2rBggUKDw+Xy+XSqFGjlJqaqpSUFNty5OXl6YsvvtCAAQP01ltvaeTIkRozZoyOHz9uW45zXn/9dXXp0kWXXHKJrXF//vlnzZ07VytWrNDnn3+uqVOnavTo0crJybEtR8eOHXXvvffqnnvu0c0336ycnBzVrFlT/v7+tuX4reLe53Y2uJ6UkZGhO+64Q9WqVdOkSZOM5OjXr5+++eYbjRkzRiNHjrzgKWRxFi5cqKCgIEVGRtoW87e6d++uJ554QrVq1ZKfn5/Gjx+vdevW2frzm5eXp08++UR33323li1bpmuuuUZjx461Lf5vJSYm6tZbby1cPbHTunXr9M477+ijjz7SunXrNHToUI0dO9bWlYABAwaoX79+uuOOOzR06NDC81JNvddx4Rzb+YSFhSk9Pb3w8enTp3X48OHCpZnyYvfu3brllltUtWpVJSYmGjlxc9++ffrqq68KH/fu3Vv+/v7as2ePLfHffPNN7dmzRwMGDCj8JT5y5EitX7/elviStHHjRn3wwQdFnrMsS35+9l0DExoaqkaNGqlDhw6Szi6D+vn5adeuXbblOOe9997TzTffbHvcdevWqU2bNmrSpIkkqX///srPz9cvv/xiW44TJ06oQ4cOWrZsmd58803dfPPNOnbsmBo0aGBbjnN+/z5PT09XlSpVCpdlypNNmzbp5ptvVocOHTR//nxVqFDB1vg7d+7Upk2bCh8PHjxY+/btK1wSt8OyZcu0fv16RUZGasyYMcrPz1dkZKRtv0s+++wzffHFF4WPLcuSj4+P7e/zyy+/vPCim0GDBiklJUWHDh2yLYd0drXk/fffN/I+l6SPP/5Y3bt3V2hoqFwul26//XZt3br1opaNf+/IkSPq27evVq5cqaSkJLVt21Y1a9ZUzZo1bcsBezi2Wevatau2bt2qHTt2SDp7lV3btm2N/A/GlP379ys6OlqDBw/WnDlzVLFiRSN5srOzFRsbqwMHDkg6Fiu4NwAAAxNJREFU+wvRx8fHtisEX3jhBb333ntavny5li9fLklavHhxYdNjh9OnTyshIaFwqe3FF19U06ZNbW0QunfvrrS0NP3www+SpA0bNuj06dOFjY9djh07ph07dqhjx462xpWk1q1ba8OGDYXf6++++055eXm2XvmbkZGh6Ojowibg6aefVq9evYz8R+Paa6/VZ599Vtiwvfzyy+rdu3e5m6D/9NNPGjFihP71r3/pn//8p5H6U1JSNHHiRB07dkyS9NZbb6lFixa2np/6wQcfaOXKlYVX6Pr6+mr58uW2vQ8PHTqkmTNnFk6zFy1apN69e9va2F533XXauHFj4VR+9erVatCgge0NyI4dO1ShQgXbf3+c07p1a61du7bw+33uinI7/w3cunWr7rrrLp0+fVr5+flauHChBgwYUG4n239ljt26o3bt2nr88cd1//33Kzc3V4GBgZozZ05Zl/WnLF68WEePHtWKFSu0YsWKwucXLVpUeEK1HVq3bq37779fo0ePlo+Pj6pXr65nn31WlStXti2HaZ06ddK4ceMUExOj/Px8hYWF6cknn7T1l0ZQUJAWLlyomTNnKicnR76+vpo3b95FbxPxeykpKapdu7btJ/5LUufOnXX33XcrJiZG/v7+CggI0DPPPGPrMTRu3FgTJkzQsGHDlJ+fr0svvVQzZ860Lf5vNWvWTJMmTdKoUaN05swZNW7cWI888oiRXCbNmzdPBQUFWrRokRYtWlT4/Ln/3Njhuuuu0+7duzVkyBD5+fmpbt26euqpp2yL7wkDBw7Unj3/v307to0QiKIo+h2RbERKAVAD2pwUIbYOAjpA2goIaG/lhCJA2Klzz0pj+ZwC5qVX+prPeDwecV1X1HUdy7Ik3WiaJp7PZ0zTFOd5xu12i3Vdkwf06/WKqqqSvvnTMAyx73uM4xhFUURZlrFtW9KNtm2j67ro+z6O44j7/R7zPCfdII2Pr3d9hQMA4Nf+1q0BAOCfEWsAABkTawAAGRNrAAAZE2sAABkTawAAGRNrAAAZE2sAABkTawAAGfsGjcmROpk9H9MAAAAASUVORK5CYII=\n", 409 | "text/plain": [ 410 | "
" 411 | ] 412 | }, 413 | "metadata": {}, 414 | "output_type": "display_data" 415 | } 416 | ], 417 | "source": [ 418 | "cmap = sns.cubehelix_palette(50, hue=0.05, rot=0, light=0.0, dark=1.2, as_cmap=True)\n", 419 | "figure(num=None, figsize=(10, 7), dpi=80, facecolor='w', edgecolor='k')\n", 420 | "ax = sns.heatmap(win_all_b, linewidth=0.01, cmap=cmap)\n", 421 | "plt.show()" 422 | ] 423 | }, 424 | { 425 | "cell_type": "code", 426 | "execution_count": null, 427 | "metadata": {}, 428 | "outputs": [], 429 | "source": [] 430 | } 431 | ], 432 | "metadata": { 433 | "kernelspec": { 434 | "display_name": "Python 3", 435 | "language": "python", 436 | "name": "python3" 437 | }, 438 | "language_info": { 439 | "codemirror_mode": { 440 | "name": "ipython", 441 | "version": 3 442 | }, 443 | "file_extension": ".py", 444 | "mimetype": "text/x-python", 445 | "name": "python", 446 | "nbconvert_exporter": "python", 447 | "pygments_lexer": "ipython3", 448 | "version": "3.7.2" 449 | } 450 | }, 451 | "nbformat": 4, 452 | "nbformat_minor": 2 453 | } 454 | --------------------------------------------------------------------------------