Improved performance tracking.

This commit is contained in:
Frederic Fortier
2017-08-18 16:02:08 -04:00
parent 37a07e03e5
commit 30e15a7b8b
5 changed files with 87 additions and 52 deletions
+56 -42
View File
@@ -1,15 +1,10 @@
from catalyst.utils.run_algo import run_algorithm
from datetime import datetime
import pytz
from logbook import Logger
from catalyst.utils.run_algo import run_algorithm
from catalyst.api import (
order,
order_target_value,
order_target_percent,
symbol,
record,
cancel_order,
get_open_orders,
)
@@ -18,53 +13,67 @@ log = Logger('buy_and_hold_live')
def initialize(context):
log.info('initializing algo')
context.asset = symbol('eos_btc')
context.asset = symbol('eos_usd')
context.TARGET_HODL_RATIO = 0.8
context.RESERVE_RATIO = 1.0 - context.TARGET_HODL_RATIO
context.is_buying = True
context.TARGET_POSITIONS = 100
context.BUY_INCREMENT = 1
def handle_data(context, data):
log.info('handling bar {data}'.format(data=data))
starting_cash = context.portfolio.starting_cash
target_hodl_value = context.TARGET_HODL_RATIO * starting_cash
reserve_value = context.RESERVE_RATIO * starting_cash
log.info('starting cash: {}'.format(starting_cash))
cash = context.portfolio.cash
log.info('base currency available: {cash}'.format(cash=cash))
price = data.current(context.asset, 'price')
log.info('got price {}'.format(price))
log.info('got price {price}'.format(price=price))
# Stop buying after passing the reserve threshold
# orders = get_open_orders(context.asset) or []
# for order in orders:
# log.info('cancelling open order {}'.format(order))
# cancel_order(order)
orders = get_open_orders(context.asset)
if orders:
log.info('skipping bar until all open orders execute')
return
# Stop buying after passing the reserve threshold
cash = context.portfolio.cash
if cash <= reserve_value:
context.is_buying = False
if price * context.BUY_INCREMENT > cash:
log.info('not enough base currency to consider buying')
return
log.info('cash {}'.format(cash))
is_buy = False
cost_basis = None
if context.asset in context.portfolio.positions:
position = context.portfolio.positions[context.asset]
cost_basis = position.cost_basis
log.info(
'found {amount} positions with cost basis {cost_basis}'.format(
amount=position.amount,
cost_basis=cost_basis
)
)
if price < cost_basis:
is_buy = True
elif price > cost_basis * 1.1:
log.info('price higher than cost basis, taking profit')
order_target_percent(
asset=context.asset,
target=0,
limit_price=price * 0.95,
)
else:
log.info('no buy or sell opportunity found')
else:
is_buy = True
# Check if still buying and could (approximately) afford another purchase
if context.is_buying and cash > price:
# Place order to make position in asset equal to target_hodl_value
order(context.asset, 1, limit_price=price * 1.1)
# This works
# order_target_value(
# context.asset,
# target_hodl_value,
# limit_price=price * 1.1,
# )
# order_target_percent(
# context.asset,
# 0.01,
# limit_price=price * 1.1
# )
if is_buy:
log.info(
'buying position cheaper than cost basis {} < {}'.format(
price,
cost_basis
)
)
order(
asset=context.asset,
amount=context.BUY_INCREMENT,
limit_price=price * 1.1
)
record(
price=price,
@@ -72,6 +81,11 @@ def handle_data(context, data):
starting_cash=context.portfolio.starting_cash,
leverage=context.account.leverage,
)
context.perf_tracker.update_performance()
log.info('the performance:\n{}'.format(
context.perf_tracker.to_dict('minute')
))
pass
@@ -79,7 +93,7 @@ exchange_conn = dict(
name='bitfinex',
key='',
secret=b'',
base_currency='btc'
base_currency='usd'
)
run_algorithm(
initialize=initialize,
+8 -4
View File
@@ -40,7 +40,6 @@ class ExchangeTradingAlgorithm(TradingAlgorithm):
super(self.__class__, self).__init__(*args, **kwargs)
self.perf_tracker = None
log.info('exchange trading algorithm successfully initialized')
def _create_clock(self):
@@ -116,7 +115,9 @@ class ExchangeTradingAlgorithm(TradingAlgorithm):
def handle_data(self, data):
self.exchange.update_portfolio()
self.exchange.check_open_orders()
transactions = self.exchange.check_open_orders()
for transaction in transactions:
self.perf_tracker.process_transaction(transaction)
if self._handle_data:
self._handle_data(self, data)
@@ -137,8 +138,11 @@ class ExchangeTradingAlgorithm(TradingAlgorithm):
amount, style = self._calculate_order(asset, amount,
limit_price, stop_price, style)
return self.exchange.order(asset, amount, limit_price, stop_price,
style)
order_id = self.exchange.order(asset, amount, limit_price, stop_price,
style)
order = self.portfolio.open_orders[order_id]
self.perf_tracker.process_order(order)
return order
@api_method
def batch_market_order(self, share_counts):
+7 -6
View File
@@ -140,12 +140,13 @@ class Bitfinex(Exchange):
executed_price = float(order_status['avg_execution_price'])
if executed_price > 0 and price > 0:
# TODO: This does not really work. Find a better way.
commission = executed_price - price \
if is_buy else price - executed_price
else:
commission = None
# if executed_price > 0 and price > 0:
# # TODO: This does not really work. Find a better way.
# commission = executed_price - price \
# if is_buy else price - executed_price
# else:
# commission = None
commission = None
date = pd.Timestamp.utcfromtimestamp(float(order_status['timestamp']))
date = pytz.utc.localize(date)
+14
View File
@@ -5,6 +5,7 @@ from abc import ABCMeta, abstractmethod, abstractproperty
import pandas as pd
from catalyst.assets._assets import Asset
from catalyst.finance.order import ORDER_STATUS
from catalyst.finance.transaction import Transaction
from catalyst.errors import (
MultipleSymbolsFound,
@@ -87,6 +88,7 @@ class Exchange:
self.assets[exchange_symbol] = asset_obj
def check_open_orders(self):
transactions = list()
if self.portfolio.open_orders:
for order_id in list(self.portfolio.open_orders):
log.debug('found open order: {}'.format(order_id))
@@ -94,6 +96,17 @@ class Exchange:
log.debug('got updated order {}'.format(order))
if order.status == ORDER_STATUS.FILLED:
transaction = Transaction(
asset=order.asset,
amount=order.amount,
dt=pd.Timestamp.utcnow(),
price=order.executed_price,
order_id=order.id,
commission=order.commission
)
transactions.append(transaction)
# TODO: use the transaction to pass the executed price
self.portfolio.execute_order(order)
elif order.status == ORDER_STATUS.CANCELLED:
self.portfolio.remove_order(order)
@@ -105,6 +118,7 @@ class Exchange:
delta=delta
)
)
return transactions
@abstractmethod
def subscribe_to_market_data(self, symbol):
+2
View File
@@ -253,6 +253,8 @@ def _run(handle_data,
start=start,
end=end,
capital_base=exchange.portfolio.starting_cash,
emission_rate='minute',
data_frequency='minute'
)
# sim_params = None
else: