Compare commits

...

24 Commits

Author SHA1 Message Date
d46fe926d8 Kubernetes namespace
Some checks failed
ci / build (push) Failing after 6s
2025-02-18 17:18:20 -05:00
255dc03e57 Use Kubernetes driver
Some checks failed
ci / build (push) Failing after 1m22s
2025-02-18 17:15:52 -05:00
f2df48bced job
Some checks failed
ci / build (push) Failing after 1m40s
2025-02-14 16:37:44 -05:00
6bd6096013 catthehacker 2025-02-14 16:36:25 -05:00
f4bfb5d584 QEMU
Some checks failed
ci / docker (push) Failing after 35s
2025-02-14 11:55:39 -05:00
9a5346cfe4 Start Docker
Some checks failed
ci / docker (push) Failing after 22s
2025-02-14 11:53:53 -05:00
69b659d2cc Docker buildx
Some checks failed
ci / docker (push) Failing after 32s
2025-02-14 11:52:09 -05:00
8f72269f3e Install Docker
Some checks failed
ci / docker (push) Failing after 30s
2025-02-14 11:50:27 -05:00
0a4cb4b673 iptables
Some checks failed
ci / docker (push) Failing after 21s
2025-02-14 11:47:54 -05:00
9bb285f71e Not rootless...
Some checks failed
ci / docker (push) Failing after 20s
2025-02-14 11:46:18 -05:00
573f58fd5d Install sudo and run rootless
Some checks failed
ci / docker (push) Failing after 20s
2025-02-14 11:44:38 -05:00
2f0a4ea2e6 Rootless
Some checks failed
ci / docker (push) Failing after 17s
2025-02-14 11:23:43 -05:00
905f21eb55 Update apt
Some checks failed
ci / docker (push) Failing after 20s
2025-02-14 11:19:38 -05:00
59748d7cc8 Install sudo
Some checks failed
ci / docker (push) Failing after 5s
2025-02-14 11:18:30 -05:00
42abda02f3 Setup docker
Some checks failed
ci / docker (push) Failing after 26s
2025-02-14 11:14:12 -05:00
4e7040f6a3 Docker buildx
Some checks failed
ci / docker (push) Failing after 24s
2025-02-14 11:07:26 -05:00
cecc72b595 Run on merge
Some checks failed
ci / docker (push) Failing after 7s
2025-02-14 10:48:32 -05:00
60b6682b1c Test II
Some checks failed
ci / docker (push) Failing after 2s
2025-02-12 22:11:23 -05:00
f46fd31f34 Test
Some checks failed
ci / docker (push) Failing after 1m32s
2025-02-12 12:27:19 -05:00
141ea4e622 Update image tag
Some checks failed
ci / docker (push) Failing after 4s
2025-02-10 20:06:53 -05:00
496477a05b Use Gitea Actions to build Docker image
Some checks failed
ci / docker (push) Failing after 1m3s
2025-02-10 19:57:10 -05:00
1c4c75367d Update .env_example for Matrix device id 2025-02-09 10:49:28 -05:00
e2034cfa65 Post log messages to Matrix (#6)
Reverted to MyStrategy instead of Cerebro experiments and implemented base functionality for a Matrix logging mechanism.

Reviewed-on: #6
2025-02-09 15:48:04 +00:00
1ef6cc4857 Revert to working version 2025-01-27 20:48:24 -05:00
11 changed files with 165 additions and 63 deletions

View File

@@ -4,3 +4,9 @@ KRAKEN_API_SEC =
R_VALUE_TARGET =
INVESTMENT_COUNT =
INVESTMENT_VOLUME =
LOG_LEVEL =
MATRIX_HOMESERVER_ADDRESS =
MATRIX_USER_ID =
MATRIX_USER_PASSWORD =
MATRIX_ROOM_ID =
MATRIX_DEVICE_ID =

32
.gitea/workflows/ci.yaml Normal file
View File

@@ -0,0 +1,32 @@
name: ci
on:
push:
branches:
- develop
merge:
branches:
- main
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
with:
driver: kubernetes
driver-opts: |
namespace=gitea
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ vars.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v6
with:
push: true
tags: ericomeehan/kraken-bot:latest

View File

@@ -0,0 +1,3 @@
# Kraken bot
A Python bot for day-trading cryptocurrencies on the Kraken exchange.

49
app.py
View File

@@ -1,46 +1,19 @@
import backtrader
import krakenex
import logging
import os
import asyncio
from dotenv import load_dotenv
from pykrakenapi import KrakenAPI
from time import sleep
from kraken_bot.MovingAverageCrossOver import MA_CrossOver
from kraken_bot.KrakenBot import KrakenBot
from kraken_bot.LinearRegression import LinearRegression
from kraken_bot.MyStrategy import MyStrategy
load_dotenv()
token = os.getenv('KRAKEN_API_TOKEN')
secret = os.getenv('KRAKEN_API_SEC')
tier = os.getenv('KRAKEN_API_TIER', 'Pro')
asset_pair = os.getenv('KRAKEN_TRADABLE_ASSET_PAIR', 'XBTUSD')
interval = int(os.getenv('KRAKEN_DATA_INTERVAL', 60))
percents = float(os.getenv('CEREBRO_SIZER_PERCENTS', 50))
logger = logging.getLogger(__name__)
kraken = KrakenAPI(krakenex.API(token, secret), tier)
cerebro = backtrader.Cerebro()
market = kraken.get_tradable_asset_pairs(pair=asset_pair).iloc[0]
sleep(kraken.factor)
cerebro.broker.setcommission(commission=market.fees[0][1]/100)
ohlc, last = kraken.get_ohlc_data(asset_pair, interval=interval, since=None, ascending=True)
sleep(kraken.factor)
cerebro.adddata(backtrader.feeds.PandasData(dataname=ohlc))
account_balance = kraken.get_trade_balance(asset='ZUSD').loc['eb'].ZUSD
sleep(kraken.factor)
cerebro.broker.setcash(account_balance)
cerebro.addsizer(backtrader.sizers.PercentSizer, percents=percents)
cerebro.addstrategy(MA_CrossOver)
bot = KrakenBot(
tier = 'Pro',
model = LinearRegression(),
trading_strategy = MyStrategy()
)
if __name__ == '__main__':
start_balance = cerebro.broker.getvalue()
print('Starting Portfolio Value: %.6f' % start_balance)
x = cerebro.run()
end_balance = cerebro.broker.getvalue()
print('Final Portfolio Value: %.6f' % end_balance)
print('Percent change: %.6f' % (((end_balance - start_balance)/start_balance) * 100))
cerebro.plot(style='candlestick')
asyncio.run(bot.update(full=True))
asyncio.run(bot.execute())

View File

@@ -1,5 +1,4 @@
import krakenex
import logging
import os
import scipy
import sys
@@ -7,16 +6,14 @@ import time
from pykrakenapi import KrakenAPI
from kraken_bot.MatrixLogger import MatrixLogger
class KrakenBot(KrakenAPI):
def __init__(self, token, secret, tier, model, trading_strategy):
def __init__(self, tier, model, trading_strategy):
self.model = model
self.trading_strategy = trading_strategy
self.log = logging.getLogger(__name__)
self.log.setLevel(
getattr(logging, os.getenv('LOG_LEVEL', 'INFO'), logging.INFO)
)
self.log.addHandler(logging.StreamHandler(sys.stdout))
super().__init__(krakenex.API(token, secret), tier=tier)
self.log = MatrixLogger(str(self.__class__.__name__))
super().__init__(krakenex.API(os.getenv('KRAKEN_API_TOKEN'), os.getenv('KRAKEN_API_SEC')), tier=tier)
self.update(full=True)
def _delay_factor(self):
@@ -75,5 +72,30 @@ class KrakenBot(KrakenAPI):
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.log.info(f"Added order to %{order.type} %{order.volume} on {order.pair}")
self.update()
def update(self, full=False):
self.log.debug(f"update: full={full}")
self._update_tradable_asset_pairs()
self._filter_tradable_asset_pairs()
self._update_account_balance()
self._filter_account_balance()
self._update_trade_balance()
if full:
self._update_ohlc_data()
self.model.update(
self.tradable_asset_pairs,
self.ohlc_data
)
self.trading_strategy.update(
self.tradable_asset_pairs,
self.ohlc_data,
self.model.analysis,
self.account_balance
)
def execute(self):
self.log.debug(f"execute")
for order in self.trading_strategy.orders:
self._add_standard_order(order)

View File

@@ -1,17 +1,13 @@
import logging
import os
import pandas
from kraken_bot.Model import Model
from scipy.stats import linregress
from kraken_bot.Model import Model
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)
)
def __init__(self):
self.r_value_target = float(os.getenv('R_VALUE_TARGET'))
self.analysis = pandas.DataFrame({})
super().__init__(
interval = 1,
@@ -54,5 +50,4 @@ class LinearRegression(Model):
) 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)
self.log.debug(self.analysis)

View File

@@ -0,0 +1,62 @@
import asyncio
import logging
import os
from nio import AsyncClient, MatrixRoom, RoomMessageText
class MatrixHandler(logging.Handler):
def __init__(self):
super().__init__()
self.address = os.getenv('MATRIX_HOMESERVER_ADDRESS')
self.user_id = os.getenv('MATRIX_USER_ID')
self.user_password = os.getenv('MATRIX_USER_PASSWORD')
self.room_id = os.getenv('MATRIX_ROOM_ID')
self.device_id = os.getenv('MATRIX_DEVICE_ID')
def message_callback(self, room: MatrixRoom, event: RoomMessageText) -> None:
return
async def send_to_matrix(self, record):
client = AsyncClient(self.address, self.user_id)
await client.login(self.user_password, self.device_id)
client.add_event_callback(self.message_callback, RoomMessageText)
await client.room_send(
self.room_id,
message_type='m.room.message',
content={'msgtype': 'm.text', 'body': self.formatter.format(record)}
)
def emit(self, record):
asyncio.run(self.send_to_matrix(record))
class MatrixLogger:
def __init__(self, name):
self.log = logging.getLogger(name)
self.log.setLevel(os.getenv('LOG_LEVEL', 'INFO'))
console_handler = logging.StreamHandler()
console_handler.setLevel(os.getenv('LOG_LEVEL', 'INFO'))
console_handler.setFormatter(logging.Formatter('%(asctime)s - %(levelname)s - %(name)s - %(message)s'))
matrix_handler = MatrixHandler()
matrix_handler.setLevel(os.getenv('LOG_LEVEL', 'INFO'))
matrix_handler.setFormatter(logging.Formatter('%(levelname)s - %(name)s - %(message)s'))
self.log.addHandler(console_handler)
self.log.addHandler(matrix_handler)
def debug(self, message):
self.log.debug(message)
def info(self, message):
self.log.info(message)
def warning(self, message):
self.log.warning(message)
def error(self, message):
self.log.error(message)
def critical(self, message):
self.log.critical(message)

View File

@@ -1,9 +1,12 @@
from abc import ABC, abstractmethod
from kraken_bot.MatrixLogger import MatrixLogger
class Model(ABC):
def __init__(self, interval, ascending):
self.interval = interval
self.ascending = ascending
self.log = MatrixLogger(self.__class__.__name__)
@abstractmethod
def since():

View File

@@ -2,8 +2,8 @@ from kraken_bot.TradingStrategy import TradingStrategy
from kraken_bot.KrakenOrder import KrakenOrder
class MyStrategy(TradingStrategy):
def __init__(self, investment_count, investment_volume):
super().__init__(investment_count, investment_volume)
def __init__(self):
super().__init__()
def update(self, tradable_asset_pairs, ohlc_data, market_analysis, account_balance):
self.orders = []

View File

@@ -1,10 +1,14 @@
import os
from abc import ABC, abstractmethod
from kraken_bot.KrakenOrder import KrakenOrder
from kraken_bot.MatrixLogger import MatrixLogger
class TradingStrategy(ABC):
def __init__(self, investment_count, investment_volume):
self.investment_count = investment_count
self.investment_volume = investment_volume
def __init__(self):
self.investment_count = int(os.getenv('INVESTMENT_COUNT'))
self.investment_volume = float(os.getenv('INVESTMENT_VOLUME'))
self.log = MatrixLogger(self.__class__.__name__)
self.orders = []
@abstractmethod

View File

@@ -1,5 +1,7 @@
krakenex
matrix-nio
pykrakenapi
python-dotenv
scipy
backtrader
matplotlib