mirror of
https://github.com/wassname/catalyst.git
synced 2026-07-21 12:30:16 +08:00
Improved performance tracking.
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user