v0.0.13
This commit is contained in:
parent
404c8d1e1b
commit
3430b37280
25
app.py
Normal file
25
app.py
Normal 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)
|
@ -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'))
|
@ -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
146
kraken_bot/KrakenBot.py
Normal 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
46
kraken_bot/KrakenOrder.py
Normal 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
|
||||
})
|
58
kraken_bot/LinearRegression.py
Normal file
58
kraken_bot/LinearRegression.py
Normal 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
14
kraken_bot/Model.py
Normal 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
0
kraken_bot/__init__.py
Normal file
Loading…
Reference in New Issue
Block a user