RAPTOR v18.4: Исправлена отчетность, активированы выходные

This commit is contained in:
root
2026-04-18 23:26:45 +03:00
commit ef0958239e
312 changed files with 54247 additions and 0 deletions

View File

@@ -0,0 +1,197 @@
import logging
from datetime import datetime, timedelta
from typing import Any, Dict, List, Optional, Type, cast
import mplfinance as mpf
import numpy as np
import pandas as pd
from t_tech.invest.strategies.base.event import DataEvent, SignalEvent, StrategyEvent
from t_tech.invest.strategies.base.signal import (
CloseLongMarketOrder,
CloseShortMarketOrder,
OpenLongMarketOrder,
OpenShortMarketOrder,
OrderSignal,
Signal,
SignalDirection,
)
from t_tech.invest.strategies.moving_average.strategy_settings import (
MovingAverageStrategySettings,
)
from t_tech.invest.strategies.plotting.plotter import PlotKwargs, StrategyPlotter
logger = logging.getLogger(__name__)
class MovingAverageStrategyPlotter(StrategyPlotter):
def __init__(self, settings: MovingAverageStrategySettings):
self._was_not_executed_color = "grey"
self._settings = settings
self._signal_type_to_style_map: Dict[Type[Signal], Dict[str, Any]] = {
OpenLongMarketOrder: {
"type": "scatter",
"markersize": 50,
"marker": "^",
"color": "green",
},
CloseLongMarketOrder: {
"type": "scatter",
"markersize": 50,
"marker": "^",
"color": "black",
},
OpenShortMarketOrder: {
"type": "scatter",
"markersize": 50,
"marker": "v",
"color": "red",
},
CloseShortMarketOrder: {
"type": "scatter",
"markersize": 50,
"marker": "v",
"color": "black",
},
}
self._signal_type_to_candle_point_map = {
SignalDirection.LONG: lambda candle: candle.low,
SignalDirection.SHORT: lambda candle: candle.high,
}
def _filter_data_events(
self, strategy_events: List[StrategyEvent]
) -> List[DataEvent]:
return cast(
List[DataEvent],
list(filter(lambda e: isinstance(e, DataEvent), strategy_events)),
)
def _filter_signal_events(
self, strategy_events: List[StrategyEvent]
) -> List[SignalEvent]:
return cast(
List[SignalEvent],
list(filter(lambda e: isinstance(e, SignalEvent), strategy_events)),
)
def _get_interval_count_between_dates(
self, start: datetime, end: datetime, interval_delta: timedelta
) -> float:
return (end - start) / interval_delta
def get_candle_plot_kwargs(
self, strategy_events: List[StrategyEvent]
) -> PlotKwargs:
data_events = self._filter_data_events(strategy_events)
quotes = {
"open": [float(e.candle_event.candle.open) for e in data_events],
"close": [float(e.candle_event.candle.close) for e in data_events],
"high": [float(e.candle_event.candle.high) for e in data_events],
"low": [float(e.candle_event.candle.low) for e in data_events],
"volume": [float(e.candle_event.volume) for e in data_events],
"time": [e.candle_event.time for e in data_events],
}
df = pd.DataFrame(quotes, index=quotes["time"])
interval_count = self._get_interval_count_between_dates(
start=df["time"].idxmin(),
end=df["time"].idxmax(),
interval_delta=self._settings.candle_interval_timedelta,
)
non_trading_coefficient = len(data_events) / interval_count
mav = {
"ma_short": int(
self._settings.short_period
/ self._settings.candle_interval_timedelta
* non_trading_coefficient
),
"ma_long": int(
self._settings.long_period
/ self._settings.candle_interval_timedelta
* non_trading_coefficient
),
}
style = mpf.make_mpf_style(
base_mpf_style="charles", mavcolors=["#1f77b4", "#ff7f0e", "#2ca02c"]
)
return cast(
PlotKwargs,
{
"data": df,
"type": "candle",
"volume": True,
"mav": tuple(mav.values()),
"style": style,
"returnfig": True,
},
)
def _get_plot_for_signal_type(
self,
signal_type: Type[Signal],
signal_event_types_to_event_index: Dict[Type[Signal], Dict[int, SignalEvent]],
data_events: List[DataEvent],
was_executed_flag: bool,
) -> Optional[PlotKwargs]:
style = self._signal_type_to_style_map[signal_type]
price = [np.nan] * len(data_events)
color = style["color"]
has_signal = False
for index, signal_event in signal_event_types_to_event_index[
signal_type
].items():
if was_executed_flag == signal_event.was_executed:
has_signal = True
candle = data_events[index].candle_event.candle
signal = cast(OrderSignal, signal_event.signal)
price[index] = self._signal_type_to_candle_point_map[signal.direction](
candle
)
if not signal_event.was_executed:
color = self._was_not_executed_color
if not has_signal:
return None
style.update({"color": color})
params = {
"price": price,
"time": [e.candle_event.time for e in data_events],
}
df = pd.DataFrame(params, index=params["time"])
return cast(PlotKwargs, dict(data=df["price"], **style))
def get_signal_plot_kwargs(
self, strategy_events: List[StrategyEvent]
) -> List[PlotKwargs]:
signal_events = self._filter_signal_events(strategy_events)
data_events = self._filter_data_events(strategy_events)
data_events.sort(key=lambda e: e.time)
first_data_event, last_data_event = data_events[0], data_events[-1]
data_events_timedelta = last_data_event.time - first_data_event.time
signal_event_types_to_event_index: Dict[
Type[Signal], Dict[int, SignalEvent]
] = {}
for signal_event in signal_events:
signal_type = type(signal_event.signal)
event_index = int(
((signal_event.time - first_data_event.time) / data_events_timedelta)
* len(data_events)
)
event_index = min(event_index, len(data_events) - 1)
if signal_type not in signal_event_types_to_event_index:
signal_event_types_to_event_index[signal_type] = {}
signal_event_types_to_event_index[signal_type][event_index] = signal_event
plots = []
for was_executed_flag in [False, True]:
for signal_type in signal_event_types_to_event_index:
kwargs = self._get_plot_for_signal_type(
signal_type=signal_type,
signal_event_types_to_event_index=signal_event_types_to_event_index,
data_events=data_events,
was_executed_flag=was_executed_flag,
)
plots.append(kwargs)
return cast(List[PlotKwargs], list(filter(lambda p: p is not None, plots)))