<reponame>seii-saintway/crypto-currency-stabilizer<filename>ccstabilizer/mxc.py
# AUTOGENERATED! DO NOT EDIT! File to edit: notebooks/main-mxc.ipynb (unless otherwise specified).

__all__ = ['TEST_RATIO', 'NOTIFY_RATE', 'BACKUP_RATE', 'Trader', 'FIAT_SYMBOLS', 'MAX_USED_FIAT_MONEY_LIMIT',
           'GAINABLE_UNIT_CC_SOLD_RATIO', 'LOSSABLE_UNIT_CC_BOUGHT_RATIO', 'MIN_TRADE_FIAT_PRICE',
           'MAX_TRADE_FIAT_PRICE']

# Cell
TEST_RATIO = 1

# Cell
NOTIFY_RATE = 60 * 8
BACKUP_RATE = 1

# Cell
from decimal import Decimal
import math
from ccstabilizer import Trader as TraderBase


class Trader(TraderBase):

    def check_and_trade(self):
        status = self.status

        min_trade_fiat_money_limit = self.exchange.get_trading_specification(
            status.crypto_symbol, status.fiat_symbol
        ).get('min_trade_fiat_money_limit', 200)

        status.update(self.get_price())

        please_sell_unit_amount = 0

        if (status.sample_number % type(self).TRADE_RATE == 0 or status.sold_unit_amount == 0) and status.fiat_price_is_higher_than_average():
            please_sell_unit_amount = min(
                math.ceil(min_trade_fiat_money_limit / status.now_sell_fiat_price_without_fee / status.trade_unit),
                math.floor(status.bought_unit_amount)
            )
            cooling_interval = type(self).HAPPY_COOLING_INTERVAL

        if status.sold_unit_amount > 0 and status.now_sell_fiat_price > status.sold_average_fiat_price:
            trade_unit_amount = min(self.get_sell_unit_amount(), math.floor(status.bought_unit_amount))
            if trade_unit_amount > 0:
                please_sell_unit_amount = trade_unit_amount
                cooling_interval = type(self).HAPPY_COOLING_INTERVAL

        gained_fiat_money = status.estimate_gained_fiat_money(status.bought_unit_amount)
        if gained_fiat_money is not None and gained_fiat_money > type(self).MAX_GAIN_JPY:
            please_sell_unit_amount = math.floor(status.bought_unit_amount)
            cooling_interval = type(self).HAPPY_COOLING_INTERVAL

        if gained_fiat_money is not None and gained_fiat_money < -type(self).MAX_LOSS_JPY:
            please_sell_unit_amount = math.floor(status.bought_unit_amount)
            cooling_interval = type(self).SAD_COOLING_INTERVAL

        if status.bought_average_fiat_price is not None and status.now_sell_fiat_price < status.bought_average_fiat_price - type(self).LOSSABLE_UNIT_CC_SELL_JPY and status.get_usage() > 90/100:
            please_sell_unit_amount = math.floor(status.bought_unit_amount)
            cooling_interval = type(self).SAD_COOLING_INTERVAL

#         if status.bought_unit_amount > 0 and status.now_sell_fiat_price < self.min_unit_cc_trade_fiat_money:
#             please_sell_unit_amount = status.bought_unit_amount
#             cooling_interval = type(self).SAD_COOLING_INTERVAL

        if self.exchange.trade_fiat_money_is_larger_than_limit(
            status.crypto_symbol,
            status.fiat_symbol,
            status.trade_unit * please_sell_unit_amount,
            status.now_sell_fiat_price_without_fee
        ):
            self.sell(please_sell_unit_amount)
            status.sample_number = 0
            return cooling_interval, 'sell', please_sell_unit_amount

        please_buy_unit_amount = 0

        # TODO: self-adaptive by trend analysis
#         init_buy_jpy = status.get_max_used_fiat_money() / Decimal(math.exp(self.lossable_unit_cc_bought_ratio / (1 - self.lossable_unit_cc_bought_ratio)))
        init_buy_jpy = min_trade_fiat_money_limit * Decimal('1.5')
        status.init_buy_jpy = init_buy_jpy
#         init_buy_jpy = min_trade_fiat_money_limit * 5
        # self.exchange.has_enough_unused_fiat_money(init_buy_jpy, status.unused_fiat_money) !! status.unused_fiat_money
        if status.used_fiat_money < min_trade_fiat_money_limit and self.exchange.has_enough_unused_fiat_money(init_buy_jpy, status.unused_fiat_money) and self.has_buyable_fiat_price():
            buy_fiat_money = max(init_buy_jpy - status.used_fiat_money, min_trade_fiat_money_limit)
            please_buy_unit_amount = math.ceil(buy_fiat_money / status.now_buy_fiat_price / status.trade_unit)

        if status.used_fiat_money < init_buy_jpy and status.fiat_price_is_lower_than_average() and self.exchange.has_enough_unused_fiat_money(init_buy_jpy - status.used_fiat_money, status.unused_fiat_money) and self.has_buyable_fiat_price():
            buy_fiat_money = max(init_buy_jpy - status.used_fiat_money, min_trade_fiat_money_limit)
            please_buy_unit_amount = math.ceil(buy_fiat_money / status.now_buy_fiat_price / status.trade_unit)

        if status.used_fiat_money >= init_buy_jpy and status.fiat_price_is_lower_than_average():
            trade_unit_amount = self.get_buy_unit_amount()
            while trade_unit_amount > 0 and not self.exchange.has_enough_unused_fiat_money(status.now_buy_fiat_price * status.trade_unit * trade_unit_amount, status.unused_fiat_money):
                trade_unit_amount >>= 1
            if trade_unit_amount > 0:
                please_buy_unit_amount = trade_unit_amount

        # print(f'{status.crypto_symbol}-{status.fiat_symbol}: please_buy_fiat_money={status.now_buy_fiat_price_without_fee * status.trade_unit * please_buy_unit_amount}\n')
        if self.exchange.trade_fiat_money_is_larger_than_limit(
            status.crypto_symbol,
            status.fiat_symbol,
            status.trade_unit * please_buy_unit_amount,
            status.now_buy_fiat_price_without_fee
        ):
            self.buy(please_buy_unit_amount)
            status.sample_number = 0
            return type(self).SAMPLE_INTERVAL, 'buy', please_buy_unit_amount

        return type(self).SAMPLE_INTERVAL, 'wait', 0


Trader.SAMPLE_INTERVAL = 60

# Cell
from decimal import Decimal

FIAT_SYMBOLS = {
#     'AR': 'USDT',
#     'B20': 'USDT',
#     'BDP': 'USDT',
#     'ETH': 'USDT',
#     'FLOW': 'USDT',
    'HOPR': 'USDT',
#     'OCEAN': 'USDT',
#     'RLY': 'USDT',
#     'TARA': 'USDT',
#     'UT': 'USDT',
#     'VELO': 'USDT',
#     'VIDY': 'USDT',
#     'XLM': 'USDT',
#     'XPX': 'USDT',
#     'XRP': 'USDT',
#     'ZYRO': 'USDT',
}
MAX_USED_FIAT_MONEY_LIMIT = {
#     'AR': Decimal('1500'),
#     'B20': Decimal('0'),
#     'BDP': Decimal('0'),
#     'ETH': Decimal('1500'),
#     'FLOW': Decimal('1000'),
    'HOPR': Decimal('Infinity'),
#     'OCEAN': Decimal('1000'),
#     'RLY': Decimal('1000'),
#     'TARA': Decimal('0'),
#     'UT': Decimal('1000'),
#     'VELO': Decimal('0'),
#     'VIDY': Decimal('1000'),
#     'XLM': Decimal('1000'),
#     'XPX': Decimal('0'),
#     'XRP': Decimal('Infinity'),
#     'ZYRO': Decimal('1000'),
}
GAINABLE_UNIT_CC_SOLD_RATIO = {
#     'AR': Decimal('0.236'),
#     'B20': Decimal('0.0031'),
#     'BDP': Decimal('0.09'),
#     'ETH': Decimal('0.0131'),
#     'FLOW': Decimal('0.09'),
    'HOPR': Decimal('1000000000.00'),
#     'OCEAN': Decimal('0.0557'),
#     'RLY': Decimal('0.09'),
#     'TARA': Decimal('0.0131'),
#     'UT': Decimal('0.0131'),
#     'VELO': Decimal('0.0131'),
#     'VIDY': Decimal('0.146'),
#     'XLM': Decimal('0.09'),
#     'XPX': Decimal('0.0031'),
#     'XRP': Decimal('0.236'),
#     'ZYRO': Decimal('0.09'),
}
LOSSABLE_UNIT_CC_BOUGHT_RATIO = {
#     'AR': Decimal('0.618'),
#     'B20': Decimal('0.618'),
#     'BDP': Decimal('0.887'),
#     'ETH': Decimal('0.618'),
#     'FLOW': Decimal('0.887'),
    'HOPR': Decimal('0.999999999'),
#     'OCEAN': Decimal('0.786'),
#     'RLY': Decimal('0.786'),
#     'TARA': Decimal('0.887'),
#     'UT': Decimal('0.786'),
#     'VELO': Decimal('0.887'),
#     'VIDY': Decimal('0.618'),
#     'XLM': Decimal('0.786'),
#     'XPX': Decimal('0.786'),
#     'XRP': Decimal('0.618'),
#     'ZYRO': Decimal('0.887'),
}
MIN_TRADE_FIAT_PRICE = {
#     'AR': Decimal('0'),
#     'B20': Decimal('5'),
#     'BDP': Decimal('0'),
#     'ETH': Decimal('1300'),
#     'FLOW': Decimal('0'),
    'HOPR': Decimal('0'),
#     'OCEAN': Decimal('1'),
#     'RLY': Decimal('0'),
#     'TARA': Decimal('0'),
#     'UT': Decimal('0'),
#     'VELO': Decimal('0'),
#     'VIDY': Decimal('0'),
#     'XLM': Decimal('0'),
#     'XPX': Decimal('0'),
#     'XRP': Decimal('0'),
#     'ZYRO': Decimal('0'),
}
MAX_TRADE_FIAT_PRICE = {
#     'AR': Decimal('Infinity'),
#     'B20': Decimal('Infinity'),
#     'BDP': Decimal('Infinity'),
#     'ETH': Decimal('Infinity'),
#     'FLOW': Decimal('Infinity'),
    'HOPR': Decimal('Infinity'),
#     'OCEAN': Decimal('Infinity'),
#     'RLY': Decimal('Infinity'),
#     'TARA': Decimal('Infinity'),
#     'UT': Decimal('Infinity'),
#     'VELO': Decimal('Infinity'),
#     'VIDY': Decimal('Infinity'),
#     'XLM': Decimal('Infinity'),
#     'XPX': Decimal('Infinity'),
#     'XRP': Decimal('Infinity'),
#     'ZYRO': Decimal('Infinity'),
}

# Internal Cell
from ccstabilizer import MXC
from ccstabilizer import secrets
from ccstabilizer import Fetcher
from ccstabilizer import Notifier
from ccstabilizer import Status

# Internal Cell
Status.robot_name_prefix = 'MX-'
exchange = MXC()
fetcher = Fetcher(exchange)
notifier = Notifier(channel_name='mxc', name='Launcher')

messages = []
color = 'good'
status_list = []
for crypto_symbol in FIAT_SYMBOLS:
    fiat_symbol = FIAT_SYMBOLS[crypto_symbol]
    trading_spec = fetcher.get_trading_spec(crypto_symbol, fiat_symbol)
    if not trading_spec.get('liquid', False):
        messages.append(f'{crypto_symbol}-{fiat_symbol} detection failed\n')
        color = 'danger'
        continue
    messages.append(f'{crypto_symbol}-{fiat_symbol} detected\n')
    if 'min_trade_unit' not in trading_spec:
        raise Exception("'min_trade_unit' not in trading_spec")
    min_trade_unit = trading_spec.get('min_trade_unit', 1)
    max_used_fiat_money_limit = MAX_USED_FIAT_MONEY_LIMIT[crypto_symbol]
    status = Status(
        robot_name = f'{crypto_symbol} Robot',
        crypto_symbol = crypto_symbol,
        fiat_symbol = fiat_symbol,
        trade_unit = min_trade_unit,
        max_used_fiat_money_limit = max_used_fiat_money_limit,
    )
    status.read()
    status_list.append(status)

# notifier.send_slack(
#     ''.join(messages), 'Power by https://jhub.name/', color
# )

# Internal Cell
from ccstabilizer import BookKeeper

# Internal Cell
import time


with BookKeeper(exchange, status_list) as bookkeeper:

    trader_list = []
    notifier_list = []
    messages = []
    for status in status_list:
        trader = Trader(
            exchange = exchange,
            status = status,
            gainable_unit_cc_sold_ratio = GAINABLE_UNIT_CC_SOLD_RATIO[status.crypto_symbol],
            lossable_unit_cc_bought_ratio = LOSSABLE_UNIT_CC_BOUGHT_RATIO[status.crypto_symbol],
            min_trade_fiat_price = MIN_TRADE_FIAT_PRICE[status.crypto_symbol],
            max_trade_fiat_price = MAX_TRADE_FIAT_PRICE[status.crypto_symbol]
        )
        trader_list.append(trader)
        notifier_list.append(Notifier(channel_name='mxc', name=status.crypto_symbol))
        messages.append(f'{status.get_robot_title()} launched')

    notifier.send_slack(
        '\n'.join(messages), 'Power by https://jhub.name/', 'good'
    )

    idx = 0
    num = len(status_list)

    while __name__ == '__main__':

        status = status_list[idx]
        trader = trader_list[idx]
        notifier = notifier_list[idx]

        cooling_interval, trade_type, unit_amount = trader.check_and_trade()

        bookkeeper.fsh.write(f'{status}\n')

        time.sleep(Trader.SAMPLE_INTERVAL / num / 2 / TEST_RATIO)

        new_status_list = bookkeeper.estimate_status_list()

        messages = []
        for i, new_status in enumerate(new_status_list):
            if new_status is not status_list[i]:

                status_list[i].update(new_status)

                bookkeeper.fth.write(f'{status_list[i]}\n')
                status_list[i].write()

                messages.append(f'{status_list[i].last_transaction} => {status_list[i].get_robot_title()}')
                messages.append(f'{status_list[i]} => Support level is {trader_list[i].min_unit_cc_trade_fiat_money} {status_list[i].fiat_symbol}.\n')

        if status.bought_unit_amount == 0:
            messages.append(f'{status.get_robot_title()} terminated')
            del status_list[idx], trader_list[idx], notifier_list[idx]
            num = len(status_list)

#         if status.total_gained_fiat_money < -Trader.MAX_LOST_JPY:
#             messages.append(f'{status.get_robot_title()} terminated')
#             del status_list[idx], trader_list[idx], notifier_list[idx]
#             num = len(status_list)

        if messages == []:

            if status.sample_number % Trader.TRADE_RATE == 0:
                bookkeeper.fth.write(f'{status}\n')

            if status.sample_number % BACKUP_RATE == 0:
                status.write()

            if status.sample_number % NOTIFY_RATE == 0:
                messages.append(f'{status} => Support level is {trader.min_unit_cc_trade_fiat_money} {status.fiat_symbol}.')

        if messages:
            notifier.send_slack(
                '\n'.join(messages), 'Power by https://jhub.name/', 'good' if status.get_total_gain_fiat_money() >= 0 else 'danger'
            )

#         if num == 0:
#             break

        status.sample_number += 1
        time.sleep(Trader.SAMPLE_INTERVAL / num / 2 / TEST_RATIO)

        idx = (idx + 1) % num
# AUTOGENERATED! DO NOT EDIT! File to edit: notebooks/main-mxc.ipynb (unless otherwise specified).

__all__ = ['TEST_RATIO', 'NOTIFY_RATE', 'BACKUP_RATE', 'Trader', 'FIAT_SYMBOLS', 'MAX_USED_FIAT_MONEY_LIMIT',
           'GAINABLE_UNIT_CC_SOLD_RATIO', 'LOSSABLE_UNIT_CC_BOUGHT_RATIO', 'MIN_TRADE_FIAT_PRICE',
           'MAX_TRADE_FIAT_PRICE']

# Cell
TEST_RATIO = 1

# Cell
NOTIFY_RATE = 60 * 8
BACKUP_RATE = 1

# Cell
from decimal import Decimal
import math
from ccstabilizer import Trader as TraderBase


class Trader(TraderBase):

    def check_and_trade(self):
        status = self.status

        min_trade_fiat_money_limit = self.exchange.get_trading_specification(
            status.crypto_symbol, status.fiat_symbol
        ).get('min_trade_fiat_money_limit', 200)

        status.update(self.get_price())

        please_sell_unit_amount = 0

        if (status.sample_number % type(self).TRADE_RATE == 0 or status.sold_unit_amount == 0) and status.fiat_price_is_higher_than_average():
            please_sell_unit_amount = min(
                math.ceil(min_trade_fiat_money_limit / status.now_sell_fiat_price_without_fee / status.trade_unit),
                math.floor(status.bought_unit_amount)
            )
            cooling_interval = type(self).HAPPY_COOLING_INTERVAL

        if status.sold_unit_amount > 0 and status.now_sell_fiat_price > status.sold_average_fiat_price:
            trade_unit_amount = min(self.get_sell_unit_amount(), math.floor(status.bought_unit_amount))
            if trade_unit_amount > 0:
                please_sell_unit_amount = trade_unit_amount
                cooling_interval = type(self).HAPPY_COOLING_INTERVAL

        gained_fiat_money = status.estimate_gained_fiat_money(status.bought_unit_amount)
        if gained_fiat_money is not None and gained_fiat_money > type(self).MAX_GAIN_JPY:
            please_sell_unit_amount = math.floor(status.bought_unit_amount)
            cooling_interval = type(self).HAPPY_COOLING_INTERVAL

        if gained_fiat_money is not None and gained_fiat_money < -type(self).MAX_LOSS_JPY:
            please_sell_unit_amount = math.floor(status.bought_unit_amount)
            cooling_interval = type(self).SAD_COOLING_INTERVAL

        if status.bought_average_fiat_price is not None and status.now_sell_fiat_price < status.bought_average_fiat_price - type(self).LOSSABLE_UNIT_CC_SELL_JPY and status.get_usage() > 90/100:
            please_sell_unit_amount = math.floor(status.bought_unit_amount)
            cooling_interval = type(self).SAD_COOLING_INTERVAL

#         if status.bought_unit_amount > 0 and status.now_sell_fiat_price < self.min_unit_cc_trade_fiat_money:
#             please_sell_unit_amount = status.bought_unit_amount
#             cooling_interval = type(self).SAD_COOLING_INTERVAL

        if self.exchange.trade_fiat_money_is_larger_than_limit(
            status.crypto_symbol,
            status.fiat_symbol,
            status.trade_unit * please_sell_unit_amount,
            status.now_sell_fiat_price_without_fee
        ):
            self.sell(please_sell_unit_amount)
            status.sample_number = 0
            return cooling_interval, 'sell', please_sell_unit_amount

        please_buy_unit_amount = 0

        # TODO: self-adaptive by trend analysis
#         init_buy_jpy = status.get_max_used_fiat_money() / Decimal(math.exp(self.lossable_unit_cc_bought_ratio / (1 - self.lossable_unit_cc_bought_ratio)))
        init_buy_jpy = min_trade_fiat_money_limit * Decimal('1.5')
        status.init_buy_jpy = init_buy_jpy
#         init_buy_jpy = min_trade_fiat_money_limit * 5
        # self.exchange.has_enough_unused_fiat_money(init_buy_jpy, status.unused_fiat_money) !! status.unused_fiat_money
        if status.used_fiat_money < min_trade_fiat_money_limit and self.exchange.has_enough_unused_fiat_money(init_buy_jpy, status.unused_fiat_money) and self.has_buyable_fiat_price():
            buy_fiat_money = max(init_buy_jpy - status.used_fiat_money, min_trade_fiat_money_limit)
            please_buy_unit_amount = math.ceil(buy_fiat_money / status.now_buy_fiat_price / status.trade_unit)

        if status.used_fiat_money < init_buy_jpy and status.fiat_price_is_lower_than_average() and self.exchange.has_enough_unused_fiat_money(init_buy_jpy - status.used_fiat_money, status.unused_fiat_money) and self.has_buyable_fiat_price():
            buy_fiat_money = max(init_buy_jpy - status.used_fiat_money, min_trade_fiat_money_limit)
            please_buy_unit_amount = math.ceil(buy_fiat_money / status.now_buy_fiat_price / status.trade_unit)

        if status.used_fiat_money >= init_buy_jpy and status.fiat_price_is_lower_than_average():
            trade_unit_amount = self.get_buy_unit_amount()
            while trade_unit_amount > 0 and not self.exchange.has_enough_unused_fiat_money(status.now_buy_fiat_price * status.trade_unit * trade_unit_amount, status.unused_fiat_money):
                trade_unit_amount >>= 1
            if trade_unit_amount > 0:
                please_buy_unit_amount = trade_unit_amount

        # print(f'{status.crypto_symbol}-{status.fiat_symbol}: please_buy_fiat_money={status.now_buy_fiat_price_without_fee * status.trade_unit * please_buy_unit_amount}\n')
        if self.exchange.trade_fiat_money_is_larger_than_limit(
            status.crypto_symbol,
            status.fiat_symbol,
            status.trade_unit * please_buy_unit_amount,
            status.now_buy_fiat_price_without_fee
        ):
            self.buy(please_buy_unit_amount)
            status.sample_number = 0
            return type(self).SAMPLE_INTERVAL, 'buy', please_buy_unit_amount

        return type(self).SAMPLE_INTERVAL, 'wait', 0


Trader.SAMPLE_INTERVAL = 60

# Cell
from decimal import Decimal

FIAT_SYMBOLS = {
#     'AR': 'USDT',
#     'B20': 'USDT',
#     'BDP': 'USDT',
#     'ETH': 'USDT',
#     'FLOW': 'USDT',
    'HOPR': 'USDT',
#     'OCEAN': 'USDT',
#     'RLY': 'USDT',
#     'TARA': 'USDT',
#     'UT': 'USDT',
#     'VELO': 'USDT',
#     'VIDY': 'USDT',
#     'XLM': 'USDT',
#     'XPX': 'USDT',
#     'XRP': 'USDT',
#     'ZYRO': 'USDT',
}
MAX_USED_FIAT_MONEY_LIMIT = {
#     'AR': Decimal('1500'),
#     'B20': Decimal('0'),
#     'BDP': Decimal('0'),
#     'ETH': Decimal('1500'),
#     'FLOW': Decimal('1000'),
    'HOPR': Decimal('Infinity'),
#     'OCEAN': Decimal('1000'),
#     'RLY': Decimal('1000'),
#     'TARA': Decimal('0'),
#     'UT': Decimal('1000'),
#     'VELO': Decimal('0'),
#     'VIDY': Decimal('1000'),
#     'XLM': Decimal('1000'),
#     'XPX': Decimal('0'),
#     'XRP': Decimal('Infinity'),
#     'ZYRO': Decimal('1000'),
}
GAINABLE_UNIT_CC_SOLD_RATIO = {
#     'AR': Decimal('0.236'),
#     'B20': Decimal('0.0031'),
#     'BDP': Decimal('0.09'),
#     'ETH': Decimal('0.0131'),
#     'FLOW': Decimal('0.09'),
    'HOPR': Decimal('1000000000.00'),
#     'OCEAN': Decimal('0.0557'),
#     'RLY': Decimal('0.09'),
#     'TARA': Decimal('0.0131'),
#     'UT': Decimal('0.0131'),
#     'VELO': Decimal('0.0131'),
#     'VIDY': Decimal('0.146'),
#     'XLM': Decimal('0.09'),
#     'XPX': Decimal('0.0031'),
#     'XRP': Decimal('0.236'),
#     'ZYRO': Decimal('0.09'),
}
LOSSABLE_UNIT_CC_BOUGHT_RATIO = {
#     'AR': Decimal('0.618'),
#     'B20': Decimal('0.618'),
#     'BDP': Decimal('0.887'),
#     'ETH': Decimal('0.618'),
#     'FLOW': Decimal('0.887'),
    'HOPR': Decimal('0.999999999'),
#     'OCEAN': Decimal('0.786'),
#     'RLY': Decimal('0.786'),
#     'TARA': Decimal('0.887'),
#     'UT': Decimal('0.786'),
#     'VELO': Decimal('0.887'),
#     'VIDY': Decimal('0.618'),
#     'XLM': Decimal('0.786'),
#     'XPX': Decimal('0.786'),
#     'XRP': Decimal('0.618'),
#     'ZYRO': Decimal('0.887'),
}
MIN_TRADE_FIAT_PRICE = {
#     'AR': Decimal('0'),
#     'B20': Decimal('5'),
#     'BDP': Decimal('0'),
#     'ETH': Decimal('1300'),
#     'FLOW': Decimal('0'),
    'HOPR': Decimal('0'),
#     'OCEAN': Decimal('1'),
#     'RLY': Decimal('0'),
#     'TARA': Decimal('0'),
#     'UT': Decimal('0'),
#     'VELO': Decimal('0'),
#     'VIDY': Decimal('0'),
#     'XLM': Decimal('0'),
#     'XPX': Decimal('0'),
#     'XRP': Decimal('0'),
#     'ZYRO': Decimal('0'),
}
MAX_TRADE_FIAT_PRICE = {
#     'AR': Decimal('Infinity'),
#     'B20': Decimal('Infinity'),
#     'BDP': Decimal('Infinity'),
#     'ETH': Decimal('Infinity'),
#     'FLOW': Decimal('Infinity'),
    'HOPR': Decimal('Infinity'),
#     'OCEAN': Decimal('Infinity'),
#     'RLY': Decimal('Infinity'),
#     'TARA': Decimal('Infinity'),
#     'UT': Decimal('Infinity'),
#     'VELO': Decimal('Infinity'),
#     'VIDY': Decimal('Infinity'),
#     'XLM': Decimal('Infinity'),
#     'XPX': Decimal('Infinity'),
#     'XRP': Decimal('Infinity'),
#     'ZYRO': Decimal('Infinity'),
}

# Internal Cell
from ccstabilizer import MXC
from ccstabilizer import secrets
from ccstabilizer import Fetcher
from ccstabilizer import Notifier
from ccstabilizer import Status

# Internal Cell
Status.robot_name_prefix = 'MX-'
exchange = MXC()
fetcher = Fetcher(exchange)
notifier = Notifier(channel_name='mxc', name='Launcher')

messages = []
color = 'good'
status_list = []
for crypto_symbol in FIAT_SYMBOLS:
    fiat_symbol = FIAT_SYMBOLS[crypto_symbol]
    trading_spec = fetcher.get_trading_spec(crypto_symbol, fiat_symbol)
    if not trading_spec.get('liquid', False):
        messages.append(f'{crypto_symbol}-{fiat_symbol} detection failed\n')
        color = 'danger'
        continue
    messages.append(f'{crypto_symbol}-{fiat_symbol} detected\n')
    if 'min_trade_unit' not in trading_spec:
        raise Exception("'min_trade_unit' not in trading_spec")
    min_trade_unit = trading_spec.get('min_trade_unit', 1)
    max_used_fiat_money_limit = MAX_USED_FIAT_MONEY_LIMIT[crypto_symbol]
    status = Status(
        robot_name = f'{crypto_symbol} Robot',
        crypto_symbol = crypto_symbol,
        fiat_symbol = fiat_symbol,
        trade_unit = min_trade_unit,
        max_used_fiat_money_limit = max_used_fiat_money_limit,
    )
    status.read()
    status_list.append(status)

# notifier.send_slack(
#     ''.join(messages), 'Power by https://jhub.name/', color
# )

# Internal Cell
from ccstabilizer import BookKeeper

# Internal Cell
import time


with BookKeeper(exchange, status_list) as bookkeeper:

    trader_list = []
    notifier_list = []
    messages = []
    for status in status_list:
        trader = Trader(
            exchange = exchange,
            status = status,
            gainable_unit_cc_sold_ratio = GAINABLE_UNIT_CC_SOLD_RATIO[status.crypto_symbol],
            lossable_unit_cc_bought_ratio = LOSSABLE_UNIT_CC_BOUGHT_RATIO[status.crypto_symbol],
            min_trade_fiat_price = MIN_TRADE_FIAT_PRICE[status.crypto_symbol],
            max_trade_fiat_price = MAX_TRADE_FIAT_PRICE[status.crypto_symbol]
        )
        trader_list.append(trader)
        notifier_list.append(Notifier(channel_name='mxc', name=status.crypto_symbol))
        messages.append(f'{status.get_robot_title()} launched')

    notifier.send_slack(
        '\n'.join(messages), 'Power by https://jhub.name/', 'good'
    )

    idx = 0
    num = len(status_list)

    while __name__ == '__main__':

        status = status_list[idx]
        trader = trader_list[idx]
        notifier = notifier_list[idx]

        cooling_interval, trade_type, unit_amount = trader.check_and_trade()

        bookkeeper.fsh.write(f'{status}\n')

        time.sleep(Trader.SAMPLE_INTERVAL / num / 2 / TEST_RATIO)

        new_status_list = bookkeeper.estimate_status_list()

        messages = []
        for i, new_status in enumerate(new_status_list):
            if new_status is not status_list[i]:

                status_list[i].update(new_status)

                bookkeeper.fth.write(f'{status_list[i]}\n')
                status_list[i].write()

                messages.append(f'{status_list[i].last_transaction} => {status_list[i].get_robot_title()}')
                messages.append(f'{status_list[i]} => Support level is {trader_list[i].min_unit_cc_trade_fiat_money} {status_list[i].fiat_symbol}.\n')

        if status.bought_unit_amount == 0:
            messages.append(f'{status.get_robot_title()} terminated')
            del status_list[idx], trader_list[idx], notifier_list[idx]
            num = len(status_list)

#         if status.total_gained_fiat_money < -Trader.MAX_LOST_JPY:
#             messages.append(f'{status.get_robot_title()} terminated')
#             del status_list[idx], trader_list[idx], notifier_list[idx]
#             num = len(status_list)

        if messages == []:

            if status.sample_number % Trader.TRADE_RATE == 0:
                bookkeeper.fth.write(f'{status}\n')

            if status.sample_number % BACKUP_RATE == 0:
                status.write()

            if status.sample_number % NOTIFY_RATE == 0:
                messages.append(f'{status} => Support level is {trader.min_unit_cc_trade_fiat_money} {status.fiat_symbol}.')

        if messages:
            notifier.send_slack(
                '\n'.join(messages), 'Power by https://jhub.name/', 'good' if status.get_total_gain_fiat_money() >= 0 else 'danger'
            )

#         if num == 0:
#             break

        status.sample_number += 1
        time.sleep(Trader.SAMPLE_INTERVAL / num / 2 / TEST_RATIO)

        idx = (idx + 1) % num
# AUTOGENERATED! DO NOT EDIT! File to edit: notebooks/main-mxc.ipynb (unless otherwise specified). # Cell # Cell # Cell #         if status.bought_unit_amount > 0 and status.now_sell_fiat_price < self.min_unit_cc_trade_fiat_money: #             please_sell_unit_amount = status.bought_unit_amount #             cooling_interval = type(self).SAD_COOLING_INTERVAL # TODO: self-adaptive by trend analysis #         init_buy_jpy = status.get_max_used_fiat_money() / Decimal(math.exp(self.lossable_unit_cc_bought_ratio / (1 - self.lossable_unit_cc_bought_ratio))) #         init_buy_jpy = min_trade_fiat_money_limit * 5 # self.exchange.has_enough_unused_fiat_money(init_buy_jpy, status.unused_fiat_money) !! status.unused_fiat_money # print(f'{status.crypto_symbol}-{status.fiat_symbol}: please_buy_fiat_money={status.now_buy_fiat_price_without_fee * status.trade_unit * please_buy_unit_amount}\n') # Cell #     'AR': 'USDT', #     'B20': 'USDT', #     'BDP': 'USDT', #     'ETH': 'USDT', #     'FLOW': 'USDT', #     'OCEAN': 'USDT', #     'RLY': 'USDT', #     'TARA': 'USDT', #     'UT': 'USDT', #     'VELO': 'USDT', #     'VIDY': 'USDT', #     'XLM': 'USDT', #     'XPX': 'USDT', #     'XRP': 'USDT', #     'ZYRO': 'USDT', #     'AR': Decimal('1500'), #     'B20': Decimal('0'), #     'BDP': Decimal('0'), #     'ETH': Decimal('1500'), #     'FLOW': Decimal('1000'), #     'OCEAN': Decimal('1000'), #     'RLY': Decimal('1000'), #     'TARA': Decimal('0'), #     'UT': Decimal('1000'), #     'VELO': Decimal('0'), #     'VIDY': Decimal('1000'), #     'XLM': Decimal('1000'), #     'XPX': Decimal('0'), #     'XRP': Decimal('Infinity'), #     'ZYRO': Decimal('1000'), #     'AR': Decimal('0.236'), #     'B20': Decimal('0.0031'), #     'BDP': Decimal('0.09'), #     'ETH': Decimal('0.0131'), #     'FLOW': Decimal('0.09'), #     'OCEAN': Decimal('0.0557'), #     'RLY': Decimal('0.09'), #     'TARA': Decimal('0.0131'), #     'UT': Decimal('0.0131'), #     'VELO': Decimal('0.0131'), #     'VIDY': Decimal('0.146'), #     'XLM': Decimal('0.09'), #     'XPX': Decimal('0.0031'), #     'XRP': Decimal('0.236'), #     'ZYRO': Decimal('0.09'), #     'AR': Decimal('0.618'), #     'B20': Decimal('0.618'), #     'BDP': Decimal('0.887'), #     'ETH': Decimal('0.618'), #     'FLOW': Decimal('0.887'), #     'OCEAN': Decimal('0.786'), #     'RLY': Decimal('0.786'), #     'TARA': Decimal('0.887'), #     'UT': Decimal('0.786'), #     'VELO': Decimal('0.887'), #     'VIDY': Decimal('0.618'), #     'XLM': Decimal('0.786'), #     'XPX': Decimal('0.786'), #     'XRP': Decimal('0.618'), #     'ZYRO': Decimal('0.887'), #     'AR': Decimal('0'), #     'B20': Decimal('5'), #     'BDP': Decimal('0'), #     'ETH': Decimal('1300'), #     'FLOW': Decimal('0'), #     'OCEAN': Decimal('1'), #     'RLY': Decimal('0'), #     'TARA': Decimal('0'), #     'UT': Decimal('0'), #     'VELO': Decimal('0'), #     'VIDY': Decimal('0'), #     'XLM': Decimal('0'), #     'XPX': Decimal('0'), #     'XRP': Decimal('0'), #     'ZYRO': Decimal('0'), #     'AR': Decimal('Infinity'), #     'B20': Decimal('Infinity'), #     'BDP': Decimal('Infinity'), #     'ETH': Decimal('Infinity'), #     'FLOW': Decimal('Infinity'), #     'OCEAN': Decimal('Infinity'), #     'RLY': Decimal('Infinity'), #     'TARA': Decimal('Infinity'), #     'UT': Decimal('Infinity'), #     'VELO': Decimal('Infinity'), #     'VIDY': Decimal('Infinity'), #     'XLM': Decimal('Infinity'), #     'XPX': Decimal('Infinity'), #     'XRP': Decimal('Infinity'), #     'ZYRO': Decimal('Infinity'), # Internal Cell # Internal Cell # notifier.send_slack( #     ''.join(messages), 'Power by https://jhub.name/', color # ) # Internal Cell # Internal Cell #         if status.total_gained_fiat_money < -Trader.MAX_LOST_JPY: #             messages.append(f'{status.get_robot_title()} terminated') #             del status_list[idx], trader_list[idx], notifier_list[idx] #             num = len(status_list) #         if num == 0: #             break