Skip to content

Commit

Permalink
Merge pull request #6785 from hummingbot/fix/more-config-scripts
Browse files Browse the repository at this point in the history
(fix) fixed directional script bugs and added configurable pmm script
  • Loading branch information
fengtality committed Jan 19, 2024
2 parents 3057732 + ec62d3a commit 4946f21
Show file tree
Hide file tree
Showing 15 changed files with 106 additions and 7 deletions.
88 changes: 88 additions & 0 deletions scripts/simple_pmm_example_config.py
@@ -0,0 +1,88 @@
import logging
import os
from decimal import Decimal
from typing import Dict, List

from pydantic import Field

from hummingbot.client.config.config_data_types import BaseClientModel, ClientFieldData
from hummingbot.connector.connector_base import ConnectorBase
from hummingbot.core.data_type.common import OrderType, PriceType, TradeType
from hummingbot.core.data_type.order_candidate import OrderCandidate
from hummingbot.core.event.events import OrderFilledEvent
from hummingbot.strategy.script_strategy_base import ScriptStrategyBase


class SimplePMMConfig(BaseClientModel):
script_file_name: str = Field(default_factory=lambda: os.path.basename(__file__))
exchange: str = Field("kucoin_paper_trade", client_data=ClientFieldData(prompt_on_new=True, prompt=lambda mi: "Enter the exchange where the bot will trade:"))
trading_pair: str = Field("ETH-USDT", client_data=ClientFieldData(prompt_on_new=True, prompt=lambda mi: "Enter the trading pair in which the bot will place orders:"))
order_amount: Decimal = Field(0.01, client_data=ClientFieldData(prompt_on_new=True, prompt=lambda mi: "Enter the order amount (denominated in base asset):"))
bid_spread: Decimal = Field(0.001, client_data=ClientFieldData(prompt_on_new=True, prompt=lambda mi: "Enter the bid order spread (in percent):"))
ask_spread: Decimal = Field(0.001, client_data=ClientFieldData(prompt_on_new=True, prompt=lambda mi: "Enter the ask order spread (in percent):"))
order_refresh_time: int = Field(15, client_data=ClientFieldData(prompt_on_new=True, prompt=lambda mi: "Enter the order refresh time (in seconds):"))
price_type: str = Field("mid", client_data=ClientFieldData(prompt_on_new=True, prompt=lambda mi: "Enter the price type to use (mid or last):"))


class SimplePMM(ScriptStrategyBase):
"""
Configurable version of the Simple PMM Example script.
"""

create_timestamp = 0
price_source = PriceType.MidPrice

@classmethod
def init_markets(cls, config: SimplePMMConfig):
cls.markets = {config.exchange: {config.trading_pair}}
cls.price_source = PriceType.LastTrade if config.price_type == "last" else PriceType.MidPrice

def __init__(self, connectors: Dict[str, ConnectorBase], config: SimplePMMConfig):
super().__init__(connectors)
self.config = config

def on_tick(self):
if self.create_timestamp <= self.current_timestamp:
self.cancel_all_orders()
proposal: List[OrderCandidate] = self.create_proposal()
proposal_adjusted: List[OrderCandidate] = self.adjust_proposal_to_budget(proposal)
self.place_orders(proposal_adjusted)
self.create_timestamp = self.config.order_refresh_time + self.current_timestamp

def create_proposal(self) -> List[OrderCandidate]:
ref_price = self.connectors[self.config.exchange].get_price_by_type(self.config.trading_pair, self.price_source)
buy_price = ref_price * Decimal(1 - self.config.bid_spread)
sell_price = ref_price * Decimal(1 + self.config.ask_spread)

buy_order = OrderCandidate(trading_pair=self.config.trading_pair, is_maker=True, order_type=OrderType.LIMIT,
order_side=TradeType.BUY, amount=Decimal(self.config.order_amount), price=buy_price)

sell_order = OrderCandidate(trading_pair=self.config.trading_pair, is_maker=True, order_type=OrderType.LIMIT,
order_side=TradeType.SELL, amount=Decimal(self.config.order_amount), price=sell_price)

return [buy_order, sell_order]

def adjust_proposal_to_budget(self, proposal: List[OrderCandidate]) -> List[OrderCandidate]:
proposal_adjusted = self.connectors[self.config.exchange].budget_checker.adjust_candidates(proposal, all_or_none=True)
return proposal_adjusted

def place_orders(self, proposal: List[OrderCandidate]) -> None:
for order in proposal:
self.place_order(connector_name=self.config.exchange, order=order)

def place_order(self, connector_name: str, order: OrderCandidate):
if order.order_side == TradeType.SELL:
self.sell(connector_name=connector_name, trading_pair=order.trading_pair, amount=order.amount,
order_type=order.order_type, price=order.price)
elif order.order_side == TradeType.BUY:
self.buy(connector_name=connector_name, trading_pair=order.trading_pair, amount=order.amount,
order_type=order.order_type, price=order.price)

def cancel_all_orders(self):
for order in self.get_active_orders(connector_name=self.config.exchange):
self.cancel(self.config.exchange, order.trading_pair, order.client_order_id)

def did_fill_order(self, event: OrderFilledEvent):
msg = (f"{event.trade_type.name} {round(event.amount, 2)} {event.trading_pair} {self.config.exchange} at {round(event.price, 2)}")
self.log_with_clock(logging.INFO, msg)
self.notify_hb_app_with_timestamp(msg)
File renamed without changes.
Expand Up @@ -85,14 +85,19 @@ def __init__(self, connectors: Dict[str, ConnectorBase], config: DirectionalTrad

for trading_pair in config.trading_pairs.split(","):
bb_config = BollingerV1Config(
exchange="binance_perpetual",
exchange=config.exchange,
trading_pair=trading_pair,
order_levels=order_levels,
candles_config=[
CandlesConfig(connector="binance_perpetual", trading_pair=trading_pair, interval="3m", max_records=100),
CandlesConfig(connector=config.candles_exchange, trading_pair=trading_pair,
interval=config.candles_interval,
max_records=config.bb_length + 200),
],
leverage=config.leverage,
bb_length=config.bb_length, bb_std=config.bb_std, bb_long_threshold=config.bb_long_threshold, bb_short_threshold=config.bb_short_threshold,
bb_length=config.bb_length,
bb_std=config.bb_std,
bb_long_threshold=config.bb_long_threshold,
bb_short_threshold=config.bb_short_threshold,
)
controller = BollingerV1(config=bb_config)
self.controllers[trading_pair] = controller
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Expand Up @@ -89,11 +89,14 @@ def __init__(self, connectors: Dict[str, ConnectorBase], config: DirectionalTrad

for trading_pair in config.trading_pairs.split(","):
macd_bb_config = MACDBBV1Config(
exchange="binance_perpetual",
exchange=config.exchange,
trading_pair=trading_pair,
order_levels=order_levels,
candles_config=[
CandlesConfig(connector="binance_perpetual", trading_pair=trading_pair, interval="3m", max_records=100),
CandlesConfig(connector=config.candles_exchange, trading_pair=trading_pair,
interval=config.candles_interval,
max_records=config.bb_length + 200),
# we need more candles to calculate the bollinger bands
],
leverage=config.leverage,
macd_fast=config.macd_fast, macd_slow=config.macd_slow, macd_signal=config.macd_signal,
Expand Down
Expand Up @@ -87,11 +87,14 @@ def __init__(self, connectors: Dict[str, ConnectorBase], config: DirectionalTrad

for trading_pair in config.trading_pairs.split(","):
trend_follower_config = TrendFollowerV1Config(
exchange="binance_perpetual",
exchange=config.exchange,
trading_pair=trading_pair,
order_levels=order_levels,
candles_config=[
CandlesConfig(connector="binance_perpetual", trading_pair=trading_pair, interval="3m", max_records=100),
CandlesConfig(connector=config.candles_exchange,
trading_pair=trading_pair,
interval=config.candles_interval,
max_records=config.bb_length + 200),
],
leverage=config.leverage,
sma_fast=config.sma_fast, sma_slow=config.sma_slow,
Expand Down

0 comments on commit 4946f21

Please sign in to comment.