Improved daily performance tracking

This commit is contained in:
Frederic Fortier
2017-08-23 14:31:10 -04:00
parent a8763a589e
commit c902949eb2
2 changed files with 60 additions and 14 deletions
+28 -9
View File
@@ -13,6 +13,7 @@
import os
import signal
import sys
import json
from datetime import timedelta
from time import sleep
@@ -30,8 +31,8 @@ from catalyst.exchange.exchange_errors import (
ExchangePortfolioDataError,
ExchangeTransactionError
)
from catalyst.exchange.exchange_utils import get_exchange_minute_writer_root
from catalyst.exchange.exchange_utils import save_algo_object, get_algo_object
from catalyst.exchange.exchange_utils import get_exchange_minute_writer_root, \
save_algo_object, get_algo_object, append_algo_object
from catalyst.finance.performance.period import calc_period_stats
from catalyst.gens.tradesimulation import AlgorithmSimulator
from catalyst.utils.api_support import (
@@ -52,7 +53,6 @@ class ExchangeTradingAlgorithm(TradingAlgorithm):
self.exchange = kwargs.pop('exchange', None)
self.algo_namespace = kwargs.pop('algo_namespace', None)
self.orders = {}
self.minute_perfs = None
self.is_running = True
self.retry_check_open_orders = 5
@@ -93,12 +93,20 @@ class ExchangeTradingAlgorithm(TradingAlgorithm):
log.info('You pressed Ctrl+C!')
stats = pd.DataFrame(self.minute_perfs)
stats.set_index('period_close', drop=True, inplace=True)
# TODO: load from daily perf pickle files?
# See: catalyst.algorithm.TradingAlgorithm#_create_daily_stats
# stats = pd.DataFrame(self.minute_perfs)
# stats.set_index('period_close', drop=True, inplace=True)
# TODO: pyfolio is going to want the daily, just resample and pick the last row
# daily_stats = stats.resample('24H').last()
self.analyze(stats)
try:
# convert perf dict to pandas dataframe
stats = self.prepare_period_stats(
start_dt=self.sim_params.start_session,
end_dt=pd.Timestamp.utcnow()
)
self.analyze(stats)
except Exception as e:
log.warn('Unable to compute daily stats: {}'.format(e))
sys.exit(0)
@@ -295,11 +303,22 @@ class ExchangeTradingAlgorithm(TradingAlgorithm):
# Performance tracker and keep only minute and cumulative
self.perf_tracker.update_performance()
# TODO: save for future use?
minute_stats = self.prepare_period_stats(
data.current_dt, data.current_dt + timedelta(minutes=1))
log.debug('the minute performance:\n{}'.format(minute_stats))
self.minute_perfs.append(minute_stats)
today = pd.to_datetime('today', utc=True)
daily_stats = self.prepare_period_stats(
start_dt=today,
end_dt=pd.Timestamp.utcnow()
)
save_algo_object(
algo_name=self.algo_namespace,
key=today.strftime('%Y-%m-%d'),
obj=daily_stats,
rel_path='daily_perf'
)
except Exception as e:
log.warn('unable to calculate performance: {}'.format(e))
+32 -5
View File
@@ -2,6 +2,7 @@ import json
import os
import pickle
import urllib
from datetime import date, datetime
from catalyst.exchange.exchange_errors import ExchangeAuthNotFound, \
ExchangeSymbolsNotFound
@@ -75,9 +76,13 @@ def get_algo_folder(algo_name, environ=None):
return algo_folder
def get_algo_object(algo_name, key, environ=None):
algo_folder = get_algo_folder(algo_name, environ)
filename = os.path.join(algo_folder, key + '.p')
def get_algo_object(algo_name, key, environ=None, rel_path=None):
folder = get_algo_folder(algo_name, environ)
if rel_path is not None:
folder = os.path.join(folder, rel_path)
filename = os.path.join(folder, key + '.p')
if os.path.isfile(filename):
try:
@@ -89,11 +94,25 @@ def get_algo_object(algo_name, key, environ=None):
return None
def save_algo_object(algo_name, key, obj, environ=None):
def save_algo_object(algo_name, key, obj, environ=None, rel_path=None):
folder = get_algo_folder(algo_name, environ)
if rel_path is not None:
folder = os.path.join(folder, rel_path)
ensure_directory(folder)
filename = os.path.join(folder, key + '.p')
with open(filename, 'wb') as handle:
pickle.dump(obj, handle, protocol=pickle.HIGHEST_PROTOCOL)
def append_algo_object(algo_name, key, obj, environ=None):
algo_folder = get_algo_folder(algo_name, environ)
filename = os.path.join(algo_folder, key + '.p')
with open(filename, 'wb') as handle:
mode = 'a+b' if os.path.isfile(filename) else 'wb'
with open(filename, mode) as handle:
pickle.dump(obj, handle, protocol=pickle.HIGHEST_PROTOCOL)
@@ -104,3 +123,11 @@ def get_exchange_minute_writer_root(exchange_name, environ=None):
ensure_directory(minute_data_folder)
return minute_data_folder
def perf_serial(obj):
"""JSON serializer for objects not serializable by default json code"""
if isinstance(obj, (datetime, date)):
return obj.isoformat()
raise TypeError("Type %s not serializable" % type(obj))