From 9e6d85cea99c3559e74d2c2f4857c69546e40fea Mon Sep 17 00:00:00 2001 From: m5l14i11 Date: Wed, 18 Sep 2024 00:32:35 +0300 Subject: [PATCH] upd --- copilot/_actor.py | 8 +- core/events/ohlcv.py | 2 +- core/interfaces/abstract_market_repository.py | 2 +- .../abstract_position_risk_strategy.py | 2 +- core/interfaces/abstract_timeseries.py | 2 +- core/models/bar.py | 9 - core/models/candle_type.py | 10 + core/models/indicator.py | 3 +- core/models/ohlcv.py | 178 ------------------ core/models/position.py | 24 +-- core/models/position_risk.py | 2 +- core/models/signal.py | 2 +- core/models/strategy_ref.py | 2 +- core/models/timeseries_ref.py | 3 +- core/queries/copilot.py | 2 +- core/queries/ohlcv.py | 2 +- exchange/_bybit_ws.py | 4 +- executor/_paper_actor.py | 2 +- feed/_historical.py | 5 +- feed/_realtime.py | 2 +- market/_actor.py | 2 +- position/_position_factory.py | 2 +- risk/_actor.py | 7 +- service/_timeseries.py | 2 +- 24 files changed, 48 insertions(+), 231 deletions(-) delete mode 100644 core/models/bar.py create mode 100644 core/models/candle_type.py delete mode 100644 core/models/ohlcv.py diff --git a/copilot/_actor.py b/copilot/_actor.py index 8cdae302..8f208126 100644 --- a/copilot/_actor.py +++ b/copilot/_actor.py @@ -30,9 +30,9 @@ from ._prompt import ( signal_contrarian_risk_prompt, - signal_risk_pattern, signal_trend_risk_prompt, system_prompt, + signal_risk_pattern, ) CopilotEvent = Union[EvaluateSignal, EvaluateSession] @@ -171,7 +171,8 @@ async def _evaluate_signal(self, msg: EvaluateSignal) -> SignalRisk: type=risk_type, ) - bar = sorted(prev_bar + [curr_bar], key=lambda x: x.timestamp) + bar = [f"{b}" for b in sorted(prev_bar + [curr_bar], key=lambda x: x.timestamp)] + strategy_type = ( StrategyType.CONTRARIAN if "SUP" not in str(signal.strategy) @@ -258,6 +259,7 @@ async def _evaluate_session(self, msg: EvaluateSession) -> SessionRiskType: mfi = np.array(ta.volume.mfi[-LOOKBACK:]) vwap = np.array(ta.volume.vwap[-LOOKBACK:]) nvol = np.array(ta.volume.nvol[-LOOKBACK:]) + vo = np.array(ta.volume.vo[-LOOKBACK:]) yz = np.array(ta.volatility.yz[-LOOKBACK:]) tr = np.array(ta.volatility.tr[-LOOKBACK:]) @@ -279,7 +281,7 @@ async def _evaluate_session(self, msg: EvaluateSession) -> SessionRiskType: vwap, tr, nvol, - hlcc4, + vo, ) ) diff --git a/core/events/ohlcv.py b/core/events/ohlcv.py index 1f91b7c1..bc368714 100644 --- a/core/events/ohlcv.py +++ b/core/events/ohlcv.py @@ -1,6 +1,6 @@ from dataclasses import dataclass, field -from core.models.ohlcv import OHLCV +from core.models.entity.ohlcv import OHLCV from core.models.symbol import Symbol from core.models.timeframe import Timeframe diff --git a/core/interfaces/abstract_market_repository.py b/core/interfaces/abstract_market_repository.py index 7124d19b..7acef111 100644 --- a/core/interfaces/abstract_market_repository.py +++ b/core/interfaces/abstract_market_repository.py @@ -1,7 +1,7 @@ from abc import abstractmethod from core.interfaces.abstract_event_manager import AbstractEventManager -from core.models.ohlcv import OHLCV +from core.models.entity.ohlcv import OHLCV from core.models.symbol import Symbol from core.models.timeframe import Timeframe diff --git a/core/interfaces/abstract_position_risk_strategy.py b/core/interfaces/abstract_position_risk_strategy.py index 14b99300..95cbf91c 100644 --- a/core/interfaces/abstract_position_risk_strategy.py +++ b/core/interfaces/abstract_position_risk_strategy.py @@ -1,7 +1,7 @@ from abc import ABC, abstractmethod from typing import List, Tuple -from core.models.ohlcv import OHLCV +from core.models.entity.ohlcv import OHLCV from core.models.signal import SignalSide diff --git a/core/interfaces/abstract_timeseries.py b/core/interfaces/abstract_timeseries.py index 56f1b382..c7a81f20 100644 --- a/core/interfaces/abstract_timeseries.py +++ b/core/interfaces/abstract_timeseries.py @@ -1,7 +1,7 @@ from abc import ABC, abstractmethod from typing import Optional -from core.models.ohlcv import OHLCV +from core.models.entity.ohlcv import OHLCV from core.models.symbol import Symbol from core.models.timeframe import Timeframe diff --git a/core/models/bar.py b/core/models/bar.py deleted file mode 100644 index d594f57e..00000000 --- a/core/models/bar.py +++ /dev/null @@ -1,9 +0,0 @@ -from dataclasses import dataclass - -from core.models.ohlcv import OHLCV - - -@dataclass(frozen=True) -class Bar: - ohlcv: OHLCV - closed: bool diff --git a/core/models/candle_type.py b/core/models/candle_type.py new file mode 100644 index 00000000..7c13911b --- /dev/null +++ b/core/models/candle_type.py @@ -0,0 +1,10 @@ +from enum import Enum, auto + + +class CandleType(Enum): + BULLISH = auto() + BEARISH = auto() + NEUTRAL = auto() + + def __str__(self): + return self.name.upper() diff --git a/core/models/indicator.py b/core/models/indicator.py index 303d8180..a26240d8 100644 --- a/core/models/indicator.py +++ b/core/models/indicator.py @@ -1,11 +1,10 @@ -from abc import ABC from dataclasses import asdict, dataclass, fields from enum import Enum from typing import Any @dataclass(frozen=True) -class Indicator(ABC): +class Indicator: type: Any def to_dict(self) -> dict: diff --git a/core/models/ohlcv.py b/core/models/ohlcv.py deleted file mode 100644 index b9a61416..00000000 --- a/core/models/ohlcv.py +++ /dev/null @@ -1,178 +0,0 @@ -from dataclasses import dataclass -from enum import Enum, auto -from typing import Any, Dict, List - - -class CandleType(Enum): - BULLISH = auto() - BEARISH = auto() - NEUTRAL = auto() - - def __str__(self): - return self.name.upper() - - -@dataclass(frozen=True) -class OHLCV: - timestamp: int - open: float - high: float - low: float - close: float - volume: float - - def __post_init__(self): - if not ( - self.low <= self.open <= self.high and self.low <= self.close <= self.high - ): - raise ValueError( - "Open and Close prices must be between Low and High prices" - ) - if self.low > self.high: - raise ValueError("Low price cannot be higher than High price") - - @classmethod - def from_list(cls, data: List[Any]) -> "OHLCV": - timestamp, open, high, low, close, volume = data - - return cls( - int(timestamp), - float(open), - float(high), - float(low), - float(close), - float(volume), - ) - - @classmethod - def from_dict(cls, data: Dict) -> "OHLCV": - keys = [ - "start", - "timestamp", - "open", - "high", - "low", - "close", - "volume", - "confirm", - ] - - if any(key not in data for key in keys): - raise ValueError(f"Data dictionary must contain the keys: {keys}") - - confirmed = ["start", "open", "high", "low", "close", "volume"] - not_confirmed = ["timestamp", "open", "high", "low", "close", "volume"] - - ohlcv_keys = not_confirmed if not data["confirm"] else confirmed - - return cls.from_list([data[key] for key in ohlcv_keys]) - - @property - def real_body(self) -> float: - return abs(self.open - self.close) - - @property - def upper_shadow(self) -> float: - return self.high - max(self.open, self.close) - - @property - def lower_shadow(self) -> float: - return min(self.open, self.close) - self.low - - @property - def price_range(self) -> float: - return self.high - self.low - - @property - def price_movement(self) -> float: - return self.close - self.open - - @property - def body_range_ratio(self) -> float: - return self.real_body / self.price_range if self.price_range != 0 else 0 - - @property - def body_shadow_ratio(self) -> float: - total_shadow = self.upper_shadow + self.lower_shadow - return self.real_body / total_shadow if total_shadow != 0 else 0 - - @property - def shadow_range_ratio(self) -> float: - total_shadow = self.upper_shadow + self.lower_shadow - return total_shadow / self.price_range if self.price_range != 0 else 0 - - @property - def real_body_normalized(self) -> float: - return self.real_body / self.price_range if self.price_range != 0 else 0 - - @property - def type(self) -> CandleType: - if self.price_movement > 0: - return CandleType.BULLISH - - if self.price_movement < 0: - return CandleType.BEARISH - - return CandleType.NEUTRAL - - def __lt__(self, other: object): - if not isinstance(other, OHLCV): - return NotImplemented - - return self.timestamp < other.timestamp - - def __eq__(self, other): - if not isinstance(other, OHLCV): - return False - - return ( - self.timestamp == other.timestamp - and self.open == other.open - and self.high == other.high - and self.low == other.low - and self.close == other.close - and self.volume == other.volume - ) - - def to_dict(self): - return { - "timestamp": self.timestamp, - "open": self.open, - "high": self.high, - "low": self.low, - "close": self.close, - "volume": self.volume, - "real_body": self.real_body, - "upper_shadow": self.upper_shadow, - "lower_shadow": self.lower_shadow, - "price_range": self.price_range, - "price_movement": self.price_movement, - "body_range_ratio": self.body_range_ratio, - "body_shadow_ratio": self.body_shadow_ratio, - "shadow_range_ratio": self.shadow_range_ratio, - "real_body_normalized": self.real_body_normalized, - "type": str(self.type), - } - - def __str__(self) -> str: - return ( - f"timestamp={self.timestamp}, " - f"open={self.open}, " - f"high={self.high}, " - f"low={self.low}, " - f"close={self.close}, " - f"volume={self.volume}, " - f"real_body={self.real_body:.8f}, " - f"upper_shadow={self.upper_shadow:.8f}, " - f"lower_shadow={self.lower_shadow:.8f}, " - f"price_range={self.price_range:.8f}, " - f"price_movement={self.price_movement:.8f}, " - f"body_range_ratio={self.body_range_ratio:.8f}, " - f"body_shadow_ratio={self.body_shadow_ratio:.8f}, " - f"shadow_range_ratio={self.shadow_range_ratio:.8f}, " - f"real_body_normalized={self.real_body_normalized:.8f}, " - f"type={self.type}" - ) - - def __repr__(self) -> str: - return f"OHLCV({self})" diff --git a/core/models/position.py b/core/models/position.py index 6932db4c..d31146de 100644 --- a/core/models/position.py +++ b/core/models/position.py @@ -6,7 +6,7 @@ import numpy as np -from .ohlcv import OHLCV +from .entity.ohlcv import OHLCV from .order import Order, OrderStatus from .position_risk import PositionRisk from .profit_target import ProfitTarget @@ -356,29 +356,21 @@ def target_filter(target, tp): dist_ratio = dist / entry_price is_exit = session_risk == SessionRiskType.EXIT - trail_threshold = 0.0008 + trail_threshold = 0.0011 if dist > trl_dist and trl_ratio > trail_threshold: logger.info("Activating trailing stop mechanism") next_position = next_position.trail(ta) if is_exit: - exit_ratio = exit_dist / entry_price dist_ratio = dist / entry_price - if exit_ratio > 0.005: - next_position = next_position.trail(ta) - - logger.info( - f"TRAIL NEXT SL: {next_position.stop_loss:.6f}, " - f"CURR PRICE: {next_position.risk_bar.close:.6f}" - ) - else: - logger.info( - f"Exit condition not met: " - f"CURR_DIST: {dist:.6f} ({dist_ratio:.2%}), " - f"EXIT_DIST: {exit_dist:.6f} ({exit_ratio:.2%})" - ) + next_position = next_position.trail(ta) + + logger.info( + f"TRAIL NEXT SL: {next_position.stop_loss:.6f}, " + f"CURR PRICE: {next_position.risk_bar.close:.6f}" + ) next_sl = next_position.stop_loss next_risk = next_position.position_risk diff --git a/core/models/position_risk.py b/core/models/position_risk.py index e6b60bbc..0d0e1591 100644 --- a/core/models/position_risk.py +++ b/core/models/position_risk.py @@ -13,7 +13,7 @@ ) from sklearn.preprocessing import MinMaxScaler, StandardScaler -from .ohlcv import OHLCV +from .entity.ohlcv import OHLCV from .risk_type import PositionRiskType from .side import PositionSide from .ta import TechAnalysis diff --git a/core/models/signal.py b/core/models/signal.py index d77f5082..84973a8a 100644 --- a/core/models/signal.py +++ b/core/models/signal.py @@ -1,6 +1,6 @@ from dataclasses import dataclass, field -from .ohlcv import OHLCV +from .entity.ohlcv import OHLCV from .side import SignalSide from .strategy import Strategy from .symbol import Symbol diff --git a/core/models/strategy_ref.py b/core/models/strategy_ref.py index 9dae9a0a..70f8f3a9 100644 --- a/core/models/strategy_ref.py +++ b/core/models/strategy_ref.py @@ -14,7 +14,7 @@ GoShortSignalReceived, ) from core.models.action import Action -from core.models.ohlcv import OHLCV +from core.models.entity.ohlcv import OHLCV from core.models.side import SignalSide from core.models.signal import Signal from core.models.strategy import Strategy diff --git a/core/models/timeseries_ref.py b/core/models/timeseries_ref.py index f95eed30..0c0b0adf 100644 --- a/core/models/timeseries_ref.py +++ b/core/models/timeseries_ref.py @@ -8,7 +8,8 @@ if typing.TYPE_CHECKING: from wasmtime import Instance, Store -from .ohlcv import OHLCV +from core.models.entity.ohlcv import OHLCV + from .ta import TechAnalysis diff --git a/core/queries/copilot.py b/core/queries/copilot.py index fc846b80..28e05e28 100644 --- a/core/queries/copilot.py +++ b/core/queries/copilot.py @@ -2,7 +2,7 @@ from typing import List from core.events.base import EventMeta -from core.models.ohlcv import OHLCV +from core.models.entity.ohlcv import OHLCV from core.models.risk_type import SessionRiskType from core.models.side import PositionSide from core.models.signal import Signal diff --git a/core/queries/ohlcv.py b/core/queries/ohlcv.py index 0c05945b..f229114f 100644 --- a/core/queries/ohlcv.py +++ b/core/queries/ohlcv.py @@ -2,7 +2,7 @@ from typing import List from core.events.base import EventMeta -from core.models.ohlcv import OHLCV +from core.models.entity.ohlcv import OHLCV from core.models.symbol import Symbol from core.models.ta import TechAnalysis from core.models.timeframe import Timeframe diff --git a/exchange/_bybit_ws.py b/exchange/_bybit_ws.py index 0fc6c4dd..962830cc 100644 --- a/exchange/_bybit_ws.py +++ b/exchange/_bybit_ws.py @@ -6,8 +6,8 @@ from websockets.exceptions import ConnectionClosedError from core.interfaces.abstract_ws import AbstractWS -from core.models.bar import Bar -from core.models.ohlcv import OHLCV +from core.models.entity.bar import Bar +from core.models.entity.ohlcv import OHLCV from core.models.timeframe import Timeframe from infrastructure.retry import retry diff --git a/executor/_paper_actor.py b/executor/_paper_actor.py index 813e2007..368427df 100644 --- a/executor/_paper_actor.py +++ b/executor/_paper_actor.py @@ -10,7 +10,7 @@ PositionInitialized, ) from core.mixins import EventHandlerMixin -from core.models.ohlcv import OHLCV +from core.models.entity.ohlcv import OHLCV from core.models.order import Order, OrderStatus, OrderType from core.models.position import Position from core.models.side import PositionSide diff --git a/feed/_historical.py b/feed/_historical.py index e1d5b809..3941f399 100644 --- a/feed/_historical.py +++ b/feed/_historical.py @@ -7,13 +7,14 @@ from core.interfaces.abstract_config import AbstractConfig from core.interfaces.abstract_exchange import AbstractExchange from core.interfaces.abstract_timeseries import AbstractTimeSeriesService -from core.models.bar import Bar +from core.models.entity.bar import Bar +from core.models.entity.ohlcv import OHLCV from core.models.lookback import Lookback -from core.models.ohlcv import OHLCV from core.models.symbol import Symbol from core.models.timeframe import Timeframe + class AsyncHistoricalData: def __init__( self, diff --git a/feed/_realtime.py b/feed/_realtime.py index 4cf8acbf..5cf60a99 100644 --- a/feed/_realtime.py +++ b/feed/_realtime.py @@ -7,7 +7,7 @@ from core.events.ohlcv import NewMarketDataReceived from core.interfaces.abstract_timeseries import AbstractTimeSeriesService from core.interfaces.abstract_ws import AbstractWS -from core.models.bar import Bar +from core.models.entity.bar import Bar from core.models.symbol import Symbol from core.models.timeframe import Timeframe diff --git a/market/_actor.py b/market/_actor.py index 68e57639..8a236258 100644 --- a/market/_actor.py +++ b/market/_actor.py @@ -3,7 +3,7 @@ from core.actors import BaseActor from core.interfaces.abstract_timeseries import AbstractTimeSeriesService from core.mixins import EventHandlerMixin -from core.models.ohlcv import OHLCV +from core.models.entity.ohlcv import OHLCV from core.models.ta import TechAnalysis from core.queries.ohlcv import TA, BackNBars, NextBar, PrevBar diff --git a/position/_position_factory.py b/position/_position_factory.py index 3903948f..8a8d0dab 100644 --- a/position/_position_factory.py +++ b/position/_position_factory.py @@ -5,7 +5,7 @@ from core.interfaces.abstract_config import AbstractConfig from core.interfaces.abstract_order_size_strategy import AbstractOrderSizeStrategy from core.interfaces.abstract_position_factory import AbstractPositionFactory -from core.models.ohlcv import OHLCV +from core.models.entity.ohlcv import OHLCV from core.models.position import Position from core.models.position_risk import PositionRisk from core.models.profit_target import ProfitTarget diff --git a/risk/_actor.py b/risk/_actor.py index aff56242..96d7dfd2 100644 --- a/risk/_actor.py +++ b/risk/_actor.py @@ -22,7 +22,7 @@ ) from core.interfaces.abstract_config import AbstractConfig from core.mixins import EventHandlerMixin -from core.models.ohlcv import OHLCV +from core.models.entity.ohlcv import OHLCV from core.models.position import Position from core.models.side import PositionSide from core.models.symbol import Symbol @@ -156,11 +156,10 @@ async def _process_market( prev_bar = next_position.risk_bar next_bar = await self.ask(NextBar(self.symbol, self.timeframe, prev_bar)) - if not next_bar: - next_bar = event.ohlcv + next_bar = next_bar or event.ohlcv - diff = event.ohlcv.timestamp - next_bar.timestamp attempts = 0 + diff = event.ohlcv.timestamp - next_bar.timestamp while diff < 0 and attempts < MAX_ATTEMPTS: new_prev_bar = await self.ask( diff --git a/service/_timeseries.py b/service/_timeseries.py index aab477e1..9d171af8 100644 --- a/service/_timeseries.py +++ b/service/_timeseries.py @@ -4,7 +4,7 @@ from core.interfaces.abstract_timeseries import AbstractTimeSeriesService from core.interfaces.abstract_wasm_manager import AbstractWasmManager -from core.models.ohlcv import OHLCV +from core.models.entity.ohlcv import OHLCV from core.models.symbol import Symbol from core.models.timeframe import Timeframe from core.models.timeseries_ref import TimeSeriesRef