Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wiseplat
GitHub Repository: wiseplat/python-code
Path: blob/master/ invest-robot-contest_tinkoff-invest-volume-analysis-robot-master/utils/strategy_util.py
5931 views
1
import numpy as np
2
import pandas as pd
3
from tinkoff.invest import TradeDirection
4
5
from settings import PERCENTAGE_VOLUME_LEVEL_RANGE
6
7
8
# находится ли цена в процентном диапазоне
9
def is_price_in_range_cluster(
10
current_price: float,
11
cluster_price
12
) -> bool:
13
level_range = cluster_price * PERCENTAGE_VOLUME_LEVEL_RANGE / 100
14
increased_level = cluster_price + level_range
15
reduced_level = cluster_price - level_range
16
return reduced_level <= current_price <= increased_level
17
18
19
# объединение двух DateFrame
20
def merge_two_frames(
21
source_df: pd.DataFrame,
22
new_df: pd.DataFrame
23
) -> pd.DataFrame:
24
if new_df is None or len(new_df) == 0:
25
return source_df
26
if source_df is None or len(source_df) == 0:
27
return new_df
28
29
first_time = pd.to_datetime(new_df.iloc[0]["time"], utc=True)
30
last_time = pd.to_datetime(new_df.iloc[-1]["time"], utc=True)
31
search_condition = (source_df["time"] >= first_time) & (source_df["time"] <= last_time)
32
33
result_df = source_df.drop(source_df.loc[search_condition].index)
34
result_df = pd.concat([result_df, new_df]).rename_axis("index")
35
return result_df.sort_values(["time", "index"]).reset_index(drop=True)
36
37
38
# расчет процентного соотношения лонгистов/шортистов в свече
39
def calculate_ratio(candles: pd.DataFrame) -> pd.DataFrame:
40
difference = candles["high"] - candles["low"]
41
long_ratio = (candles["close"] - candles["low"]) / difference * 100
42
short_ratio = (candles["high"] - candles["close"]) / difference * 100
43
candles["long"] = long_ratio
44
candles["short"] = short_ratio
45
46
# расчет расположения макс. объема относительно открытия свечи
47
from_high = abs(candles["high"] - candles["max_volume_price"])
48
from_low = abs(candles["max_volume_price"] - candles["low"])
49
total = from_high + from_low
50
candles.loc[candles["direction"] == TradeDirection.TRADE_DIRECTION_BUY, "percent"] = from_low / total * 100
51
candles.loc[candles["direction"] == TradeDirection.TRADE_DIRECTION_SELL, "percent"] = from_high / total * 100
52
53
# определение победителя:
54
# если соотношение лонгистов больше и макс объем как можно ниже, то приоритет для лонга
55
# если соотношение шортистов больше и макс объем как можно выше, то приоритет для шорта
56
# todo вынести значения в константы
57
candles.loc[candles["direction"] == TradeDirection.TRADE_DIRECTION_BUY, "win"] = (candles["long"] > 50) & (
58
candles["percent"] <= 40)
59
candles.loc[candles["direction"] == TradeDirection.TRADE_DIRECTION_SELL, "win"] = (candles["short"] > 50) & (
60
candles["percent"] <= 40)
61
62
return candles
63
64
65
# агрегация данных для получения свечи
66
def agg_ohlc(df: pd.DataFrame) -> pd.Series:
67
if df.empty:
68
return pd.Series({
69
"low": np.nan,
70
"high": np.nan,
71
"open": np.nan,
72
"close": np.nan,
73
"total_volume": np.nan,
74
"max_volume_price": np.nan
75
})
76
price = df["price"].values
77
quantity = df["quantity"].values
78
return pd.Series({
79
"low": min(price),
80
"high": max(price),
81
"open": price[0],
82
"close": price[-1],
83
"total_volume": sum(quantity),
84
"max_volume_price": df.groupby(["price"])[["quantity"]].sum().idxmax()[0]
85
})
86
87
88
# преобразование тиковых данных в свечи с максимальным объемом
89
def ticks_to_cluster(
90
df: pd.DataFrame,
91
period: str = "1min"
92
) -> pd.DataFrame:
93
candles = df.set_index(["time"])
94
candles = candles.resample(period).apply(agg_ohlc)
95
candles = candles.ffill()
96
97
candles["time"] = candles.index
98
# свеча доджи
99
candles.loc[candles["close"] == candles["open"], "direction"] = TradeDirection.TRADE_DIRECTION_UNSPECIFIED
100
# бычья свеча
101
candles.loc[candles["close"] > candles["open"], "direction"] = TradeDirection.TRADE_DIRECTION_BUY
102
# медвежья свеча
103
candles.loc[candles["open"] > candles["close"], "direction"] = TradeDirection.TRADE_DIRECTION_SELL
104
105
candles = candles[["time", "open", "close", "high", "low", "total_volume", "direction", "max_volume_price"]]
106
return candles.reset_index(drop=True)
107
108
109
# получение подходящего и не подходящего времени из сформированных
110
# точек входов для последующего отображения на графике
111
def processed_volume_levels_to_times(processed_volume_levels):
112
valid_entry_points = []
113
invalid_entry_points = []
114
if processed_volume_levels is None:
115
return valid_entry_points, invalid_entry_points
116
117
for price, volume_level in processed_volume_levels.items():
118
for time, is_success in volume_level["times"].items():
119
if is_success:
120
valid_entry_points += [time]
121
else:
122
invalid_entry_points += [time]
123
124
return valid_entry_points, invalid_entry_points
125
126
127
def apply_frame_type(df: pd.DataFrame) -> pd.DataFrame:
128
return df.astype({
129
"figi": "object",
130
"direction": "int64",
131
"price": "float64",
132
"quantity": "int64",
133
# "time": "datetime64[ms]",
134
})
135
136
137
def create_empty_df() -> pd.DataFrame:
138
df = pd.DataFrame(columns=["figi", "direction", "price", "quantity", "time"])
139
df.time = pd.to_datetime(df.time, unit="ms")
140
df.price = pd.to_numeric(df.price)
141
df.quantity = pd.to_numeric(df.quantity)
142
return df
143
144