Hodler Strategy

Now, let's implement a basic Hodler strategy and Binance Hodler. In this step, we'll define which entities need to be registered into the strategy and the policy for this strategy. Each strategy should implement the set_up and predict methods.

from typing import List
from dataclasses import dataclass

from fractal.core.base import (
    BaseStrategy, Action, BaseStrategyParams,
    ActionToTake, NamedEntity, Observation)
from fractal.core.entities import BaseSpotEntity
from fractal.loaders import BinanceDayPriceLoader, LoaderType

from binance_entity import BinanceSpot, BinanceGlobalState


@dataclass
class HolderStrategyParams(BaseStrategyParams):
    BUY_PRICE: float
    SELL_PRICE: float
    TRADE_SHARE: float = 0.01
    INITIAL_BALANCE: float = 10_000


class HodlerStrategy(BaseStrategy):

    def __init__(self, debug: bool = False, params: HolderStrategyParams | None = None):
        super().__init__(params=params, debug=debug)

    def set_up(self):
        # check that the entity 'exchange' is registered
        assert 'exchange' in self.get_all_available_entities()
        # deposit initial balance into the exchange
        if self._params is not None:
            self.__deposit_into_exchange()

    def predict(self) -> ActionToTake:
        exchange: BaseSpotEntity = self.get_entity('exchange')
        if exchange.global_state.price < self._params.BUY_PRICE:
            # Emit a buy action to apply to the entity registered as 'exchange'
            # We buy a fraction of the total cash available
            amount_to_buy = self._params.TRADE_SHARE * exchange.internal_state.cash / exchange.global_state.price
            if amount_to_buy < 1e-6:
                return []
            return [ActionToTake(
                entity_name='exchange',
                action=Action(action='buy', args={'amount': amount_to_buy})
            )]
        elif exchange.global_state.price > self._params.SELL_PRICE:
            # Emit a sell action to apply to the entity registered as 'exchange'
            # We sell a fraction of the total BTC available
            amount_to_sell = self._params.TRADE_SHARE * exchange.internal_state.amount
            if amount_to_sell < 1e-6:
                return []
            return [ActionToTake(
                entity_name='exchange',
                action=Action(action='sell', args={'amount': amount_to_sell})
            )]
        else:
            # HODL
            return []

    def __deposit_into_exchange(self):
        exchange: BaseSpotEntity = self.get_entity('exchange')
        action: Action = Action(action='deposit', args={'amount_in_notional': self._params.INITIAL_BALANCE})
        exchange.execute(action)


class BinanceHodlerStrategy(HodlerStrategy):
    def set_up(self):
        self.register_entity(NamedEntity(entity_name='exchange', entity=BinanceSpot()))
        super().set_up()

Last updated