Source code for babao.inputs.ledger.ledgerManager
"""
Manage all the ledgers and give some utils functions to check balance
or buy/sell
"""
import re
from typing import Optional, Dict, Union, TYPE_CHECKING # noqa: F401
import babao.config as conf
import babao.inputs.trades.krakenTradesInput as tra
import babao.utils.date as du
import babao.utils.log as log
from babao.utils.enum import ActionEnum, CryptoEnum, QuoteEnum # noqa: F401
MIN_BAL = 50 # maximum drawdown # TODO: this should be a percent of... hmm
if TYPE_CHECKING:
from babao.inputs.ledger.ledgerInputBase import ABCLedgerInput # noqa: F401
AssetEnum = Union["CryptoEnum", "QuoteEnum"]
LEDGERS = None # type: Optional[Dict[AssetEnum, ABCLedgerInput]]
TRADES = None # type: Optional[Dict[CryptoEnum, ABCLedgerInput]]
[docs]def initLedgers():
"""
Instantiate all the ledgers and corresponding trade-inputs needed
by conf.CRYPTOS / conf.QUOTE
"""
global LEDGERS
global TRADES
log_to_file = conf.CURRENT_COMMAND != "train"
simulate = conf.CURRENT_COMMAND != "wetRun"
temp = conf.CURRENT_COMMAND == "backtest"
if simulate:
import babao.inputs.ledger.fakeLedgerInput as led
else:
import babao.inputs.ledger.krakenLedgerInput as led
pat = ".*(" + conf.QUOTE.name + "|" + "|".join(
[c.name for c in conf.CRYPTOS]
) + ")"
ledgers = [
led.__dict__[k](log_to_file, temp)
for k in led.__dict__ if re.match(pat, k)
]
if conf.CURRENT_COMMAND != "fetch" and simulate \
and sum([l.balance for l in ledgers]) == 0:
ledgers[0].deposit(ledgers[0].__class__(log_to_file=False), 100)
for l in ledgers[1:]:
l.deposit(l.__class__(log_to_file=False), 0)
LEDGERS = {l.asset: l for l in ledgers}
TRADES = {
l.asset: tra.__dict__[next(
k for k in tra.__dict__
if l.asset.name in k and conf.QUOTE.name in k
)]() for l in ledgers[1:]
}
[docs]def getBalanceInQuote(crypto_enum):
"""Convert to quote the balance of the LEDGERS[crypto_enum]"""
return LEDGERS[crypto_enum].balance * TRADES[crypto_enum].current_row.price
[docs]def getGlobalBalanceInQuote():
"""Sum and convert to quote the balance of all your LEDGERS"""
return sum(
(getBalanceInQuote(c) for c in TRADES)
) + LEDGERS[conf.QUOTE].balance
[docs]def getLastTx():
"""Return the timestamp of the last transaction in all LEDGERS"""
return max((l.last_tx for l in LEDGERS.values()))
[docs]def gameOver():
"""Check if you're broke"""
return getGlobalBalanceInQuote() < MIN_BAL
def _tooSoon(timestamp):
"""
Check if the previous transaction was too soon to start another one
The delay is based on conf.TIME_INTERVAL.
"""
last_tx = getLastTx()
if last_tx > 0 \
and timestamp - last_tx < du.secToNano(3 * conf.TIME_INTERVAL * 60):
if LEDGERS[conf.QUOTE].verbose:
log.warning("Previous transaction was too soon, waiting")
return True
return False
def _canBuy():
"""
Check if you can buy crypto
This is based on your balance and your current position.
"""
# if LAST_TX["type"] == "b":
# return False
if LEDGERS[conf.QUOTE].balance < MIN_BAL:
if LEDGERS[conf.QUOTE].verbose:
log.warning("Not enough", conf.QUOTE.name, "to buy")
return False
return True
def _canSell(crypto_enum):
"""
Check if you can sell crypto
This is based on your balance and your current position.
"""
# if LAST_TX["type"] == "s":
# return False
if getBalanceInQuote(crypto_enum) < MIN_BAL:
# this can be quite high actually
# support.kraken.com/ \
# hc/en-us/articles/205893708-What-is-the-minimum-order-size-
if LEDGERS[conf.QUOTE].verbose:
log.warning("Not enough", crypto_enum.name, "to sell")
return False
return True
[docs]def buy(crypto_enum, volume):
"""Buy the given ´volume´ of ´crypto_enum´"""
timestamp = du.TIME_TRAVELER.getTime()
if not _canBuy() or _tooSoon(timestamp): # I can english tho
return False
LEDGERS[conf.QUOTE].buy(
LEDGERS[crypto_enum],
volume,
TRADES[crypto_enum].current_row.price,
timestamp
)
return True
[docs]def sell(crypto_enum, volume):
"""Sell the given ´volume´ of ´crypto_enum´"""
timestamp = du.TIME_TRAVELER.getTime()
if not _canSell(crypto_enum) or _tooSoon(timestamp):
return False
LEDGERS[conf.QUOTE].sell(
LEDGERS[crypto_enum],
volume,
TRADES[crypto_enum].current_row.price,
timestamp
)
return True
[docs]def buyOrSell(action_enum, crypto_enum, volume=None):
"""
Decide wether to buy or sell (or not) ´volume´ the ´crypto_enum´
based on the given ´action_enum´
It will consider the current ´ledger.BALANCE´, and evenutally update it.
"""
if action_enum == ActionEnum.BUY:
if volume is None:
volume = LEDGERS[conf.QUOTE].balance
return buy(crypto_enum, volume)
if action_enum == ActionEnum.SELL:
if volume is None:
volume = LEDGERS[crypto_enum].balance
return sell(crypto_enum, volume)
return False