mirror of
https://github.com/d0zingcat/deploy.git
synced 2026-05-13 15:09:33 +00:00
(feat) update deploy script to add max portfolio loss
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
import os
|
import os
|
||||||
import time
|
import time
|
||||||
|
from decimal import Decimal
|
||||||
from typing import Dict, List, Optional, Set
|
from typing import Dict, List, Optional, Set
|
||||||
|
|
||||||
from pydantic import Field
|
from pydantic import Field
|
||||||
@@ -19,6 +20,8 @@ class GenericV2StrategyWithCashOutConfig(StrategyV2ConfigBase):
|
|||||||
candles_config: List[CandlesConfig] = []
|
candles_config: List[CandlesConfig] = []
|
||||||
markets: Dict[str, Set[str]] = {}
|
markets: Dict[str, Set[str]] = {}
|
||||||
time_to_cash_out: Optional[int] = None
|
time_to_cash_out: Optional[int] = None
|
||||||
|
max_global_drawdown: Optional[float] = None
|
||||||
|
max_controller_drawdown: Optional[float] = None
|
||||||
|
|
||||||
|
|
||||||
class GenericV2StrategyWithCashOut(StrategyV2Base):
|
class GenericV2StrategyWithCashOut(StrategyV2Base):
|
||||||
@@ -36,6 +39,10 @@ class GenericV2StrategyWithCashOut(StrategyV2Base):
|
|||||||
super().__init__(connectors, config)
|
super().__init__(connectors, config)
|
||||||
self.config = config
|
self.config = config
|
||||||
self.cashing_out = False
|
self.cashing_out = False
|
||||||
|
self.max_pnl_by_controller = {}
|
||||||
|
self.performance_reports = {}
|
||||||
|
self.max_global_pnl = Decimal("0")
|
||||||
|
self.drawdown_exited_controllers = []
|
||||||
self.closed_executors_buffer: int = 30
|
self.closed_executors_buffer: int = 30
|
||||||
self.performance_report_interval: int = 1
|
self.performance_report_interval: int = 1
|
||||||
self._last_performance_report_timestamp = 0
|
self._last_performance_report_timestamp = 0
|
||||||
@@ -58,20 +65,58 @@ class GenericV2StrategyWithCashOut(StrategyV2Base):
|
|||||||
if self.mqtt_enabled:
|
if self.mqtt_enabled:
|
||||||
self._pub = ETopicPublisher("performance", use_bot_prefix=True)
|
self._pub = ETopicPublisher("performance", use_bot_prefix=True)
|
||||||
|
|
||||||
def on_stop(self):
|
async def on_stop(self):
|
||||||
|
await super().on_stop()
|
||||||
if self.mqtt_enabled:
|
if self.mqtt_enabled:
|
||||||
self._pub({controller_id: {} for controller_id in self.controllers.keys()})
|
self._pub({controller_id: {} for controller_id in self.controllers.keys()})
|
||||||
self._pub = None
|
self._pub = None
|
||||||
|
|
||||||
def on_tick(self):
|
def on_tick(self):
|
||||||
super().on_tick()
|
super().on_tick()
|
||||||
|
self.performance_reports = {controller_id: self.executor_orchestrator.generate_performance_report(controller_id=controller_id).dict() for controller_id in self.controllers.keys()}
|
||||||
self.control_cash_out()
|
self.control_cash_out()
|
||||||
|
self.control_max_drawdown()
|
||||||
self.send_performance_report()
|
self.send_performance_report()
|
||||||
|
|
||||||
|
def control_max_drawdown(self):
|
||||||
|
if self.config.max_controller_drawdown:
|
||||||
|
self.check_max_controller_drawdown()
|
||||||
|
if self.config.max_global_drawdown:
|
||||||
|
self.check_max_global_drawdown()
|
||||||
|
|
||||||
|
def check_max_controller_drawdown(self):
|
||||||
|
for controller_id, controller in self.controllers.items():
|
||||||
|
controller_pnl = self.performance_reports[controller_id]["global_pnl_quote"]
|
||||||
|
last_max_pnl = self.max_pnl_by_controller[controller_id]
|
||||||
|
if controller_pnl > last_max_pnl:
|
||||||
|
self.max_pnl_by_controller[controller_id] = controller_pnl
|
||||||
|
else:
|
||||||
|
current_drawdown = last_max_pnl - controller_pnl
|
||||||
|
if current_drawdown > self.config.max_controller_drawdown:
|
||||||
|
self.logger().info(f"Controller {controller_id} reached max drawdown. Stopping the controller.")
|
||||||
|
controller.stop()
|
||||||
|
executors_order_placed = self.filter_executors(
|
||||||
|
executors=self.executors_info[controller_id],
|
||||||
|
filter_func=lambda x: x.is_active and not x.is_trading,
|
||||||
|
)
|
||||||
|
self.executor_orchestrator.execute_actions(
|
||||||
|
actions=[StopExecutorAction(controller_id=controller_id, executor_id=executor.id) for executor in executors_order_placed]
|
||||||
|
)
|
||||||
|
self.drawdown_exited_controllers.append(controller_id)
|
||||||
|
|
||||||
|
def check_max_global_drawdown(self):
|
||||||
|
current_global_pnl = sum([report["global_pnl_quote"] for report in self.performance_reports.values()])
|
||||||
|
if current_global_pnl > self.max_global_pnl:
|
||||||
|
self.max_global_pnl = current_global_pnl
|
||||||
|
else:
|
||||||
|
current_global_drawdown = self.max_global_pnl - current_global_pnl
|
||||||
|
if current_global_drawdown > self.config.max_global_drawdown:
|
||||||
|
self.logger().info("Global drawdown reached. Stopping the strategy.")
|
||||||
|
HummingbotApplication.main_application().stop()
|
||||||
|
|
||||||
def send_performance_report(self):
|
def send_performance_report(self):
|
||||||
if self.current_timestamp - self._last_performance_report_timestamp >= self.performance_report_interval and self.mqtt_enabled:
|
if self.current_timestamp - self._last_performance_report_timestamp >= self.performance_report_interval and self.mqtt_enabled:
|
||||||
performance_reports = {controller_id: self.executor_orchestrator.generate_performance_report(controller_id=controller_id).dict() for controller_id in self.controllers.keys()}
|
self._pub(self.performance_reports)
|
||||||
self._pub(performance_reports)
|
|
||||||
self._last_performance_report_timestamp = self.current_timestamp
|
self._last_performance_report_timestamp = self.current_timestamp
|
||||||
|
|
||||||
def control_cash_out(self):
|
def control_cash_out(self):
|
||||||
@@ -100,6 +145,8 @@ class GenericV2StrategyWithCashOut(StrategyV2Base):
|
|||||||
[StopExecutorAction(executor_id=executor.id,
|
[StopExecutorAction(executor_id=executor.id,
|
||||||
controller_id=executor.controller_id) for executor in executors_to_stop])
|
controller_id=executor.controller_id) for executor in executors_to_stop])
|
||||||
if not controller.config.manual_kill_switch and controller.status == RunnableStatus.TERMINATED:
|
if not controller.config.manual_kill_switch and controller.status == RunnableStatus.TERMINATED:
|
||||||
|
if controller_id in self.drawdown_exited_controllers:
|
||||||
|
continue
|
||||||
self.logger().info(f"Restarting controller {controller_id}.")
|
self.logger().info(f"Restarting controller {controller_id}.")
|
||||||
controller.start()
|
controller.start()
|
||||||
|
|
||||||
@@ -129,6 +176,7 @@ class GenericV2StrategyWithCashOut(StrategyV2Base):
|
|||||||
def apply_initial_setting(self):
|
def apply_initial_setting(self):
|
||||||
connectors_position_mode = {}
|
connectors_position_mode = {}
|
||||||
for controller_id, controller in self.controllers.items():
|
for controller_id, controller in self.controllers.items():
|
||||||
|
self.max_pnl_by_controller[controller_id] = Decimal("0")
|
||||||
config_dict = controller.config.dict()
|
config_dict = controller.config.dict()
|
||||||
if "connector_name" in config_dict:
|
if "connector_name" in config_dict:
|
||||||
if self.is_perpetual(config_dict["connector_name"]):
|
if self.is_perpetual(config_dict["connector_name"]):
|
||||||
|
|||||||
Reference in New Issue
Block a user