Skip to content

Commit

Permalink
refactor: restructure project
Browse files Browse the repository at this point in the history
  • Loading branch information
Primexz committed May 12, 2024
1 parent a1b8a60 commit c3ec56b
Show file tree
Hide file tree
Showing 7 changed files with 144 additions and 140 deletions.
35 changes: 17 additions & 18 deletions bot/bot.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,23 +15,22 @@ type Bot struct {
lastBtcFiatPrice float64
fiatAmount float64
initialRun bool

log *logger.Logger
krakenApi *kraken.KrakenApi
}

func NewBot() *Bot {
return &Bot{
initialRun: true,
log: logger.NewLogger("bot"),
krakenApi: kraken.NewKrakenApi(),
}
}

var log *logger.Logger

func init() {
log = logger.NewLogger("bot")
}

func (b *Bot) StartBot() {
go func() {
log.Info("Starting bot")
b.log.Info("Starting bot")

for {
b.run()
Expand All @@ -44,37 +43,37 @@ func (b *Bot) StartBot() {
}

func (b *Bot) run() {
if fiatAmnt, err := kraken.GetFiatBalance(); err == nil {
if fiatAmnt, err := b.krakenApi.GetFiatBalance(); err == nil {
b.fiatAmount = fiatAmnt
} else {
log.Error("Error getting fiat balance: ", err)
b.log.Error("Error getting fiat balance: ", err)
return
}

if b.fiatAmount == 0 {
log.Warn("No remaining fiat balance found. It's time to top up your account ;)")
b.log.Warn("No remaining fiat balance found. It's time to top up your account ;)")
return
}

newFiatMoney := b.fiatAmount > b.lastFiatBalance
if newFiatMoney || b.initialRun {
if b.initialRun {
log.Info("Initial run. Calculating next fiat deposit day..")
b.log.Info("Initial run. Calculating next fiat deposit day..")
} else {
log.Info("New fiat deposit found. 💰")
b.log.Info("New fiat deposit found. 💰")
}

b.timeOfEmptyFiat = computeNextFiatDepositDay()

log.Info("Next Fiat deposit required at", b.timeOfEmptyFiat)
b.log.Info("Next Fiat deposit required at", b.timeOfEmptyFiat)

b.lastFiatBalance = b.fiatAmount
}

if fiatPrice, err := kraken.GetCurrentBtcFiatPrice(); err == nil {
if fiatPrice, err := b.krakenApi.GetCurrentBtcFiatPrice(); err == nil {
b.lastBtcFiatPrice = fiatPrice
} else {
log.Error("Error getting current btc price:", err)
b.log.Error("Error getting current btc price:", err)
return
}

Expand All @@ -83,11 +82,11 @@ func (b *Bot) run() {
}

if (b.timeOfNextOrder.Before(time.Now()) || newFiatMoney) && !b.initialRun {
log.Info("Placing bitcoin purchase order. ₿")
b.log.Info("Placing bitcoin purchase order. ₿")

kraken.BuyBtc(0)
b.krakenApi.BuyBtc(0)
b.calculateTimeOfNextOrder()
}

log.Info("Next order in", fmtDuration(time.Until(b.timeOfNextOrder)))
b.log.Info("Next order in", fmtDuration(time.Until(b.timeOfNextOrder)))
}
2 changes: 1 addition & 1 deletion bot/calculations.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ func (b *Bot) calculateTimeOfNextOrder() {
orderAmountUntilRefill := b.getOrderAmountUntilRefill()

if orderAmountUntilRefill < 1 {
log.Error("Fiat balance is too low to make an order.")
b.log.Error("Fiat balance is too low to make an order.")
b.timeOfNextOrder = b.timeOfEmptyFiat
return
}
Expand Down
3 changes: 2 additions & 1 deletion config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,10 @@ var log *logger.Logger

func init() {
log = logger.NewLogger("config")
loadConfiguration()
}

func LoadConfiguration() {
func loadConfiguration() {
log.Info("Loading configuration..")

KrakenPublicKey = loadRequiredEnvVariable("KRAKEN_PUBLIC_KEY")
Expand Down
12 changes: 4 additions & 8 deletions kraken/balance.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,26 +6,22 @@ import (
"github.com/primexz/KrakenDCA/config"
)

func GetFiatBalance() (float64, error) {
func (k *KrakenApi) GetFiatBalance() (float64, error) {
var balanceKey string
if config.Currency == "AUD" {
balanceKey = "Z"
} else {
balanceKey = config.FiatPrefix + config.Currency
}

return getKrakenBalance(balanceKey)
}

func getKrakenBalance(currency string) (float64, error) {
balances, err := getApi().GetAccountBalances()
balances, err := k.api.GetAccountBalances()
if err != nil {
return 0, err
}

balance, ok := balances[currency]
balance, ok := balances[balanceKey]
if !ok {
return 0, fmt.Errorf("no balance found for currency %s", currency)
return 0, fmt.Errorf("no balance found for currency %s", balanceKey)
}

ret, _ := balance.Float64()
Expand Down
120 changes: 10 additions & 110 deletions kraken/kraken_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,19 @@ package kraken

import (
"encoding/json"
"fmt"
"io"
"net/http"
"strconv"
"strings"
"time"

"github.com/aopoltorzhicky/go_kraken/rest"
"github.com/primexz/KrakenDCA/config"
"github.com/primexz/KrakenDCA/logger"
"github.com/primexz/KrakenDCA/notification"
)

var log *logger.Logger
type KrakenApi struct {
api *rest.Kraken

func init() {
log = logger.NewLogger("kraken_api")
log *logger.Logger
}

type KrakenSpread struct {
Expand All @@ -27,7 +23,13 @@ type KrakenSpread struct {
Last int `json:"last"`
}

func GetCurrentBtcFiatPrice() (float64, error) {
func NewKrakenApi() *KrakenApi {
return &KrakenApi{
api: rest.New(config.KrakenPublicKey, config.KrakenPrivateKey),
}
}

func (k *KrakenApi) GetCurrentBtcFiatPrice() (float64, error) {
cryptoName := config.CryptoPrefix + "XBT" + config.FiatPrefix + config.Currency

resp, err := http.Get("https://api.kraken.com/0/public/Spread?pair=" + cryptoName)
Expand Down Expand Up @@ -56,105 +58,3 @@ func GetCurrentBtcFiatPrice() (float64, error) {

return parsedPrice, nil
}

func BuyBtc(_retry_do_not_use int) {
if _retry_do_not_use > 5 {
log.Error("Failed to buy btc after 5 retries, stop recursion")
return
}

currency := config.Currency

fiatPrice, err := GetCurrentBtcFiatPrice()
if err != nil {
log.Error("Failed to get current btc price", err.Error())
}

var (
response rest.AddOrderResponse
krakenErr error
)

if config.ExperimentalMakerFee {
priceRound, _ := strconv.ParseFloat(fmt.Sprintf("%.1f", fiatPrice), 64)
args := map[string]interface{}{
// if set to true, no order will be submitted
"validate": false,

//price can only be specified up to 1 decimals
"price": priceRound - 0.1,
"oflags": "post",
"timeinforce": "GTD",
"expiretm": "+240", // close order after 4 minutes
}

response, krakenErr = getApi().AddOrder("xbt"+strings.ToLower(currency), "buy", "limit", config.KrakenOrderSize, args)
if krakenErr != nil {
log.Error("Failed to buy btc", krakenErr.Error())
return
}

transactionId := response.TransactionIds[0]

for {
orderInfo, err := getApi().QueryOrders(true, "", transactionId)
if err != nil {
log.Error("Failed to get order status", err.Error())
return
}

order, ok := orderInfo[transactionId]
if ok {
orderStatus := order.Status
log.Info("Order status:", orderStatus)

if orderStatus == "closed" {
log.Info("Order successfully executed")
break // don't return to send notification and log
}

if orderStatus == "canceled" && order.Reason == "User requested" {
log.Info("Order canceled by user")
return
}

if orderStatus == "canceled" && order.Reason == "Post only order" {
log.Info("Order canceled by kraken due to post only order, retrying with new order")
BuyBtc(_retry_do_not_use + 1)
return
}

if orderStatus == "canceled" {
log.Info("Unknown reason for order cancelation.")
return
}

if orderStatus == "expired" {
log.Info("Order expired, retrying with new order")
BuyBtc(_retry_do_not_use + 1)
return
}
} else {
log.Error("Failed to query order status")
}

//wait on pending, open
time.Sleep(5 * time.Second)
}

} else {
response, krakenErr = getApi().AddOrder("xbt"+strings.ToLower(currency), "buy", "market", config.KrakenOrderSize, nil)
if krakenErr != nil {
log.Error("Failed to buy btc", krakenErr.Error())
return
}
}

notification.SendPushNotification("BTC bought", fmt.Sprintf("Description: %s\nPrice: %f %s", response.Description.Info, fiatPrice, currency))

log.Info("Successfully bought btc ->", response.Description.Info, response.Description.Price)
}

func getApi() *rest.Kraken {
return rest.New(config.KrakenPublicKey, config.KrakenPrivateKey)
}
Loading

0 comments on commit c3ec56b

Please sign in to comment.