This commit is contained in:
Eric Meehan 2024-09-22 00:05:32 -04:00
parent 404c8d1e1b
commit 3430b37280
9 changed files with 289 additions and 122 deletions

25
app.py Normal file
View File

@ -0,0 +1,25 @@
import logging
import os
from kraken_bot.KrakenBot import KrakenBot
from kraken_bot.LinearRegression import LinearRegression
from dotenv import load_dotenv
load_dotenv()
logger = logging.getLogger(__name__)
bot = KrakenBot(
token = os.getenv('KRAKEN_API_TOKEN'),
secret = os.getenv('KRAKEN_API_SEC'),
tier = 'Pro',
investment_count = int(os.getenv('INVESTMENT_COUNT')),
investment_volume = float(os.getenv('INVESTMENT_VOLUME'))
)
model = LinearRegression(
r_value_target = float(os.getenv('R_VALUE_TARGET'))
)
if __name__ == '__main__':
bot.update()
bot.trade(model)

View File

@ -1,105 +0,0 @@
import krakenex
import pandas
import time
from pykrakenapi import KrakenAPI
from scipy.stats import linregress
class KrakenBot():
def __init__(self, kraken_api_token, kraken_api_sec, tier, r_value_target, investment_count, investment_volume):
self.r_value_target = r_value_target
self.investment_count = investment_count
self.investment_volume = investment_volume
k = krakenex.API(kraken_api_token, kraken_api_sec)
self.kraken = KrakenAPI(k, tier=tier)
def filter_asset_pairs(self, tradable_asset_pairs):
return tradable_asset_pairs[
(tradable_asset_pairs['quote'] == 'ZUSD') &
(tradable_asset_pairs['status'] == 'online')
]
def model_asset_pair(self, asset_pair):
ohlc = self.kraken.get_ohlc_data(asset_pair)[0]
time.sleep(self.kraken.factor)
model = pandas.DataFrame({
'open': linregress(ohlc['time'].astype(float), ohlc['open'].astype(float)),
'high': linregress(ohlc['time'].astype(float), ohlc['high'].astype(float)),
'low': linregress(ohlc['time'].astype(float), ohlc['low'].astype(float)),
'close': linregress(ohlc['time'].astype(float), ohlc['close'].astype(float))
}).transpose()
model.columns = ['slope', 'intercept', 'r_value', 'p_value', 'stderr']
return model
def grade_models(self, models):
model_averages = pandas.DataFrame({
model: {
'slope': models[model].slope.mean(),
'intercept': models[model].intercept.mean(),
'r_value': models[model].r_value.mean(),
'p_value': models[model].p_value.mean(),
'stderr': models[model].stderr.mean()
} for model in models
}).transpose()
filtered_models = model_averages[
(model_averages['r_value'] >= self.r_value_target) &
(model_averages['slope'] > 0)
]
return filtered_models.sort_values(by='slope', ascending=False)
def sell_asset(self, market, volume):
self.kraken.add_standard_order(
ordertype = 'market',
type = 'sell',
pair = market,
volume = volume,
validate = False
)
time.sleep(self.kraken.factor)
print(f"Sold {volume} on {market}")
def buy_asset(self, market, volume):
self.kraken.add_standard_order(
ordertype = 'market',
type = 'buy',
pair = market,
volume = volume,
validate = False
)
print(f"Purchased {volume} on {market}")
time.sleep(self.kraken.factor)
def update(self):
asset_pairs = self.filter_asset_pairs(self.kraken.get_tradable_asset_pairs())
time.sleep(self.kraken.factor)
graded_models = self.grade_models(
{asset_pair: self.model_asset_pair(asset_pair) for asset_pair in asset_pairs.index}
)
print(graded_models)
account_balance = self.kraken.get_account_balance()
for asset in account_balance[(account_balance.vol > 0) & (account_balance.index != 'ZUSD')].index:
market = asset_pairs[
(asset_pairs.base == asset) &
(asset_pairs.quote == 'ZUSD')
]
if market.index[0] not in graded_models[:self.investment_count * 2].index:
self.sell_asset(market.index[0], account_balance.loc[asset].vol)
account_balance = self.kraken.get_account_balance()
while ((len(account_balance[account_balance.vol > 0]) - 1 < self.investment_count) &
(account_balance.loc['ZUSD'].vol > self.investment_volume)):
for market in graded_models.index:
if asset_pairs.loc[market].base not in account_balance[account_balance.vol > 0].index:
ohlc, last = self.kraken.get_ohlc_data(market)
volume = self.investment_volume/ohlc.iloc[-1].close
try:
self.buy_asset(market, volume)
account_balance = self.kraken.get_account_balance()
time.sleep(self.kraken.factor)
break
except:
continue
print(self.kraken.get_account_balance())
print(self.kraken.get_trade_balance(asset='ZUSD'))

View File

@ -1,17 +0,0 @@
import os
from KrakenBot import KrakenBot
from dotenv import load_dotenv
load_dotenv()
bot = KrakenBot(
kraken_api_token = os.getenv('KRAKEN_API_TOKEN'),
kraken_api_sec = os.getenv('KRAKEN_API_SEC'),
tier = 'Pro',
r_value_target = float(os.getenv('R_VALUE_TARGET')),
investment_count = int(os.getenv('INVESTMENT_COUNT')),
investment_volume = float(os.getenv('INVESTMENT_VOLUME'))
)
if __name__ == '__main__':
bot.update()

146
kraken_bot/KrakenBot.py Normal file
View File

@ -0,0 +1,146 @@
import krakenex
import logging
import os
import scipy
import time
from pykrakenapi import KrakenAPI
class KrakenBot(KrakenAPI):
class KrakenOrder():
def __init__(self, ordertype, type, pair, userref=None, volume=None, price=None, price2=None, trigger=None, leverage=None,
oflags=None, timeinforce=None, starttm=0, expiretm=0, close_ordertype=None, close_price=None, close_price2=None,
deadline=None, validate=True, otp=None):
self.ordertype = ordertype
self.type = type
self.pair = pair
self.userref = userref
self.volume = volume
self.price = price
self.price2 = price2
self.trigger = trigger
self.leverage = leverage
self.oflags = oflags
self.timeinforce = timeinforce
self.starttm = starttm
self.expiretm = expiretm
self.close_ordertype = close_ordertype
self.close_price = close_price
self.close_price2 = close_price2
self.deadline = deadline
self.validate = validate
self.otp = otp
def __str__(self):
return str({
'ordertype': self.ordertype,
'type': self.type,
'pair': self.pair,
'userref': self.userref,
'volume': self.volume,
'price': self.price,
'price2': self.price2,
'trigger': self.trigger,
'leverage': self.leverage,
'oflags': self.oflags,
'timeinforce': self.timeinforce,
'starttm': self.starttm,
'expiretm': self.expiretm,
'close_ordertype': self.close_ordertype,
'close_price': self.close_price,
'close_price2': self.close_price2,
'deadline': self.deadline,
'validate': self.validate,
'otp': self.otp
})
def __init__(self, token, secret, tier, investment_count, investment_volume):
self.investment_count = investment_count
self.investment_volume = investment_volume
self.log = logging.getLogger(__name__)
self.log.setLevel(
getattr(logging, os.getenv('LOG_LEVEL', 'INFO'), logging.INFO)
)
super().__init__(krakenex.API(token, secret), tier=tier)
self.update()
def _delay_factor(self):
self.log.debug(f"_delay_factor")
time.sleep(self.factor)
self.log.debug(f"Delayed {self.factor} seconds")
def _update_tradable_asset_pairs(self, info=None, pair=None):
self.log.debug(f"update_tradable_asset_pairs: info={info}, pair={pair}")
self._delay_factor()
self.tradable_asset_pairs = self.get_tradable_asset_pairs(info, pair)
def _update_account_balance(self, otp=None):
self.log.debug(f"update_account_balance: otp={otp}")
self._delay_factor()
self.account_balance = self.get_account_balance(otp)
self.log.debug(self.account_balance)
def _update_trade_balance(self, aclass='currency', asset='ZUSD', otp=None):
self.log.debug(f"update_trade_balance: aclass={aclass}, asset={asset}, otp={otp}")
self._delay_factor()
self.trade_balance = self.get_trade_balance(aclass, asset, otp)
self.log.debug(self.trade_balance)
def _get_ohlc_data(self, pair, interval=1, since=None, ascending=False):
self.log.debug(f"get_ohlc_data: pair={pair}, interval={interval}, since={since}, ascending={ascending}")
self._delay_factor()
return self.get_ohlc_data(pair, interval, since, ascending)
def _add_standard_order(self, order):
self.log.debug(f"add_standard_order: order={order}")
self._delay_factor()
order = self.add_standard_order(
order.ordertype, order.type, order.pair, order.userref, order.volume, order.price, order.price2, order.trigger,
order.leverage, order.oflags, order.timeinforce, order.starttm, order.expiretm, order.close_ordertype,
order.close_price, order.close_price2, order.deadline, order.validate, order.otp)
self.log.info(order)
self.update()
def update(self):
self.log.debug(f"update")
self._update_tradable_asset_pairs()
self._update_account_balance()
self._update_trade_balance()
def trade(self, model):
self.log.debug(f"trade")
model.update(
self.tradable_asset_pairs,
{
asset_pair: self._get_ohlc_data(
asset_pair, model.interval, model.since(), model.ascending
) for asset_pair in self.tradable_asset_pairs.index
}
)
for asset in self.account_balance[(self.account_balance.index != 'ZUSD') & (self.account_balance.vol > 0)].index:
market = self.tradable_asset_pairs[
(self.tradable_asset_pairs.base == asset) &
(self.tradable_asset_pairs.quote == 'ZUSD')
].iloc[0]
if market.altname not in model.analysis.index:
self._add_standard_order(self.KrakenOrder(
ordertype = 'market',
type = 'sell',
pair = market.altname,
volume = self.account_balance.loc[asset].vol,
validate = False
))
while ((len(self.account_balance[self.account_balance.vol > 0]) - 1 < self.investment_count) &
(self.account_balance.loc['ZUSD'].vol > self.investment_volume)):
for market in model.analysis.index:
if self.tradable_asset_pairs.loc[market].base not in self.account_balance[self.account_balance.vol > 0].index:
ohlc, last = self._get_ohlc_data(market)
volume = self.investment_volume / ohlc.iloc[-1].close
self._add_standard_order(self.KrakenOrder(
ordertype = 'market',
type = 'buy',
pair = market,
volume = volume,
validate = False
))
break

46
kraken_bot/KrakenOrder.py Normal file
View File

@ -0,0 +1,46 @@
class KrakenOrder():
def __init__(self, ordertype, type, pair, userref=None, volume=None, price=None, price2=None, trigger=None, leverage=None,
oflags=None, timeinforce=None, starttm=0, expiretm=0, closeordertype=None, close_price=None, close_price2=None,
deadline=None, validate=True, otp=None):
self.ordertype = ordertype
self.type = type
self.pair = pair
self.userref = userref
self.volume = volume
self.price = price
self.price2 = price2
self.trigger = trigger
self.leverage = leverage
self.oflags = oflags
self.timeinforce = timeinforce
self.starttm = starttm
self.expiretm = expiretm
self.closeordertype = closeordertype
self.close_price = close_price
self.close_price2 = clowe_price2
self.deadline = deadline
self.validate = validate
self.otp = otp
def __str__(self):
return str({
'ordertype': self.ordertype
'type': self.type
'pair': self.pair
'userref': self.userref
'volume': self.volume
'price': self.price
'price2': self.price2
'trigger': self.trigger
'leverage': self.leverage
'oflags': self.oflags
'timeinforce': self.timeinforce
'starttm': self.starttm
'expiretm': self.expiretm
'closeordertype': self.closeordertype
'close_price': self.close_price
'close_price2': self.clowe_price2
'deadline': self.deadline
'validate': self.validate
'otp': self.otp
})

View File

@ -0,0 +1,58 @@
import logging
import os
import pandas
from kraken_bot.Model import Model
from scipy.stats import linregress
class LinearRegression(Model):
def __init__(self, r_value_target):
self.r_value_target = r_value_target
self.log = logging.getLogger(__name__)
self.log.setLevel(
getattr(logging, os.getenv('LOG_LEVEL', 'INFO'), logging.INFO)
)
self.analysis = pandas.DataFrame({})
super().__init__(
interval = 1,
ascending = False
)
def _linear_regression_for_ohlc_data(self, ohlc_data):
self.log.debug(f"_linear_regression_for_ohlc_data: ohlc_data=...")
return linregress(ohlc_data['time'].astype(float), ohlc_data['close'].astype(float))
def _filter_asset_pairs(self, tradable_asset_pairs):
self.log.debug(f"_filter_asset_pairs: tradable_asset_pairs=...")
return tradable_asset_pairs[
(tradable_asset_pairs['quote'] == 'ZUSD') &
(tradable_asset_pairs['status'] == 'online')
]
def _filter_regressions(self, regressions):
self.log.debug(f"_filter_regressions: regressions=...")
regressions.columns = ['slope', 'intercept', 'r_value', 'p_value', 'stderr']
return regressions[
(regressions.r_value >= self.r_value_target) &
(regressions.slope > 0)
]
def _order_regressions(self, regressions):
self.log.debug(f"_order_regressions: regressions=...")
return regressions.sort_values(by='slope', ascending=False)
def since(self):
return None
def update(self, tradable_asset_pairs, ohlc_data):
self.log.debug(f"update: tradable_asset_pairs=..., ohlc_data=...")
self.analysis = self._order_regressions(
self._filter_regressions(
pandas.DataFrame({
asset_pair: self._linear_regression_for_ohlc_data(
ohlc_data[asset_pair][0]
) for asset_pair in self._filter_asset_pairs(tradable_asset_pairs).index
}).transpose()
))
self.log.info(f"Completed linear regression analysis of OHLC market data")
self.log.info(self.analysis)

14
kraken_bot/Model.py Normal file
View File

@ -0,0 +1,14 @@
from abc import ABC, abstractmethod
class Model(ABC):
def __init__(self, interval, ascending):
self.interval = interval
self.ascending = ascending
@abstractmethod
def since():
pass
@abstractmethod
def update(self, tradable_asset_pairs, ohlc_data, account_balance, trade_balance):
pass

0
kraken_bot/__init__.py Normal file
View File