Beispiel #1
0
    def balance(self, prices: typing.List[TokenValue]):
        padding = "\n    "

        def balances_report(balances) -> str:
            return padding.join(list([f"{bal}" for bal in balances]))

        current_balances = self._fetch_balances()
        total_value = Decimal(0)
        for bal in current_balances:
            price = TokenValue.find_by_token(prices, bal.token)
            value = bal.value * price.value
            total_value += value
        self.logger.info(f"Starting balances: {padding}{balances_report(current_balances)} - total: {total_value}")
        resolved_targets: typing.List[TokenValue] = []
        for target in self.target_balances:
            price = TokenValue.find_by_token(prices, target.token)
            resolved_targets += [target.resolve(price.value, total_value)]

        balance_changes = calculate_required_balance_changes(current_balances, resolved_targets)
        self.logger.info(f"Full balance changes: {padding}{balances_report(balance_changes)}")

        dont_bother = FilterSmallChanges(self.action_threshold, current_balances, prices)
        filtered_changes = list(filter(dont_bother.allow, balance_changes))
        self.logger.info(f"Filtered balance changes: {padding}{balances_report(filtered_changes)}")
        if len(filtered_changes) == 0:
            self.logger.info("No balance changes to make.")
            return

        sorted_changes = sort_changes_for_trades(filtered_changes)
        self._make_changes(sorted_changes)
        updated_balances = self._fetch_balances()
        self.logger.info(f"Finishing balances: {padding}{balances_report(updated_balances)}")
Beispiel #2
0
def calculate_required_balance_changes(current_balances: typing.List[TokenValue], desired_balances: typing.List[TokenValue]) -> typing.List[TokenValue]:
    changes: typing.List[TokenValue] = []
    for desired in desired_balances:
        current = TokenValue.find_by_token(current_balances, desired.token)
        change = TokenValue(desired.token, desired.value - current.value)
        changes += [change]

    return changes
Beispiel #3
0
    def _fetch_balances(self) -> typing.List[TokenValue]:
        balances: typing.List[TokenValue] = []
        for token in self.tokens:
            balance = TokenValue.fetch_total_value(self.context, self.wallet.address, token)
            balances += [balance]

        return balances
Beispiel #4
0
 def __init__(self, action_threshold: Decimal, balances: typing.List[TokenValue], prices: typing.List[TokenValue]):
     self.logger: logging.Logger = logging.getLogger(self.__class__.__name__)
     self.prices: typing.Dict[str, TokenValue] = {}
     total = Decimal(0)
     for balance in balances:
         price = TokenValue.find_by_token(prices, balance.token)
         self.prices[f"{price.token.mint}"] = price
         total += price.value * balance.value
     self.total_balance = total
     self.action_threshold_value = total * action_threshold
     self.logger.info(f"Wallet total balance of {total} gives action threshold value of {self.action_threshold_value}")
Beispiel #5
0
 def resolve(self, current_price: Decimal, total_value: Decimal) -> TokenValue:
     target_value = total_value * self.target_fraction
     target_size = target_value / current_price
     return TokenValue(self.token, target_size)
Beispiel #6
0
 def resolve(self, current_price: Decimal, total_value: Decimal) -> TokenValue:
     return TokenValue(self.token, self.value)
Beispiel #7
0
    btc_target = parser.parse("btc:0.05")
    prices = [Decimal("60000"), Decimal("4000"), Decimal("1")]  # Ordered as per Group index ordering
    desired_balances = []
    for target in [eth_target, btc_target]:
        token_index = group.price_index_of_token(target.token)
        price = prices[token_index]
        resolved = target.resolve(price, Decimal(10000))
        desired_balances += [resolved]

    assert(desired_balances[0].token.name == "ETH")
    assert(desired_balances[0].value == Decimal("0.5"))
    assert(desired_balances[1].token.name == "BTC")
    assert(desired_balances[1].value == Decimal("0.05"))

    current_balances = [
        TokenValue(eth, Decimal("0.6")),  # Worth $2,400 at the test prices
        TokenValue(btc, Decimal("0.01")),  # Worth $6,00 at the test prices
        TokenValue(usdt, Decimal("7000")),  # Remainder of $10,000 minus above token values
    ]

    changes = calculate_required_balance_changes(current_balances, desired_balances)
    for change in changes:
        order_type = "BUY" if change.value > 0 else "SELL"
        print(f"{change.token.name} {order_type} {change.value}")

    # To get from our current balances of 0.6 ETH and 0.01 BTC to our desired balances of
    # 0.5 ETH and 0.05 BTC, we need to sell 0.1 ETH and buy 0.04 BTC. But we want to do the sell
    # first, to make sure we have the proper liquidity when it comes to buying.
    sorted_changes = sort_changes_for_trades(changes)
    assert(sorted_changes[0].token.name == "ETH")
    assert(sorted_changes[0].value == Decimal("-0.1"))
Beispiel #8
0
    if MARGIN_ACCOUNT_TO_LIQUIDATE == "":
        raise Exception(
            "No margin account to liquidate - try setting the variable MARGIN_ACCOUNT_TO_LIQUIDATE to a margin account public key."
        )

    from Context import default_context
    from Wallet import default_wallet

    if default_wallet is None:
        print("No default wallet file available.")
    else:
        print("Wallet Balances Before:")
        group = Group.load(default_context)
        balances_before = group.fetch_balances(default_wallet.address)
        TokenValue.report(print, balances_before)

        prices = group.fetch_token_prices()
        margin_account = MarginAccount.load(
            default_context, PublicKey(MARGIN_ACCOUNT_TO_LIQUIDATE), group)
        intrinsic_balance_sheets_before = margin_account.get_intrinsic_balance_sheets(
            group)
        print("Margin Account Before:", intrinsic_balance_sheets_before)
        liquidator = ForceCancelOrdersAccountLiquidator(
            default_context, default_wallet)
        transaction_id = liquidator.liquidate(group, margin_account, prices)
        if transaction_id is None:
            print("No transaction sent.")
        else:
            print("Transaction ID:", transaction_id)
            print("Waiting for confirmation...")