openfund-maker 2.0.1__py3-none-any.whl → 2.0.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- maker/BestFVGStrategyMaker.py +220 -0
- maker/SMCStrategyMaker.py +53 -28
- maker/main.py +12 -4
- {openfund_maker-2.0.1.dist-info → openfund_maker-2.0.2.dist-info}/METADATA +1 -1
- {openfund_maker-2.0.1.dist-info → openfund_maker-2.0.2.dist-info}/RECORD +7 -6
- {openfund_maker-2.0.1.dist-info → openfund_maker-2.0.2.dist-info}/WHEEL +0 -0
- {openfund_maker-2.0.1.dist-info → openfund_maker-2.0.2.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,220 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
import traceback
|
3
|
+
import pandas as pd
|
4
|
+
|
5
|
+
from maker.SMCStrategyMaker import SMCStrategyMaker
|
6
|
+
|
7
|
+
|
8
|
+
class BestFVGStrategyMaker(SMCStrategyMaker):
|
9
|
+
def __init__(self, config, platform_config, feishu_webhook=None,logger=None):
|
10
|
+
super().__init__(config, platform_config, feishu_webhook, logger)
|
11
|
+
self.place_order_prices = {} # 记录每个symbol的挂单价格
|
12
|
+
self.htf_last_CHoCH = {} #记录HTF的CHoCH struct
|
13
|
+
|
14
|
+
def check_price_in_fvg(self, df, side, fvg):
|
15
|
+
"""
|
16
|
+
检查最大或最小价格是否在FVG范围内
|
17
|
+
Args:
|
18
|
+
htf_last_side: str, 方向 'buy' or 'sell'
|
19
|
+
fvg_top: float, FVG上边界
|
20
|
+
fvg_bot: float, FVG下边界
|
21
|
+
Returns:
|
22
|
+
bool: 是否在FVG范围内
|
23
|
+
"""
|
24
|
+
if fvg is None:
|
25
|
+
return False
|
26
|
+
|
27
|
+
fvg_top = fvg["top"]
|
28
|
+
fvg_bot = fvg["bot"]
|
29
|
+
fvg_index = fvg["index"]
|
30
|
+
|
31
|
+
# 检查价格是否在FVG范围内,bar_index 是从fvg_index+2开始
|
32
|
+
if side == 'buy':
|
33
|
+
# 多头趋势检查最低价是否进入FVG区域
|
34
|
+
min_price = min(df['low'].iloc[fvg_index+2:])
|
35
|
+
return min_price <= fvg_top
|
36
|
+
else:
|
37
|
+
# 空头趋势检查最高价是否进入FVG区域
|
38
|
+
max_price = max(df['high'].iloc[fvg_index+2:])
|
39
|
+
return fvg_bot <= max_price
|
40
|
+
|
41
|
+
|
42
|
+
def process_pair(self,symbol,pair_config):
|
43
|
+
self.logger.info("=" * 60)
|
44
|
+
"""_summary_
|
45
|
+
1. HTF 判断struct趋势
|
46
|
+
2. HTF 获取最新的两个极值点,设置折价区和溢价区
|
47
|
+
3. HTF 在折价区找FVG,监控价格是否进入FVG
|
48
|
+
|
49
|
+
4. LTF 判断struct趋势是否有CHoCH
|
50
|
+
5. LTF 寻找FVG,下单
|
51
|
+
"""
|
52
|
+
try:
|
53
|
+
# 检查是否有持仓,有持仓不进行下单
|
54
|
+
if self.check_position(symbol=symbol) :
|
55
|
+
self.logger.info(f"{symbol} : 有持仓合约,不进行下单。")
|
56
|
+
if symbol in self.place_order_prices:
|
57
|
+
self.place_order_prices[symbol] = {}
|
58
|
+
return
|
59
|
+
|
60
|
+
|
61
|
+
smc_strategy = pair_config.get('smc_strategy',{})
|
62
|
+
|
63
|
+
# 获取历史K线,HTF和CTF
|
64
|
+
htf = str(smc_strategy.get('HTF','15m'))
|
65
|
+
ltf = str(smc_strategy.get('LTF', '1m'))
|
66
|
+
htf_Klines = self.get_historical_klines(symbol=symbol, bar=htf)
|
67
|
+
htf_df = self.format_klines(htf_Klines)
|
68
|
+
|
69
|
+
enable_FVG = smc_strategy.get('enable_FVG',True) # 是否启用FVG
|
70
|
+
enable_OB = smc_strategy.get('enable_OB',True) # 是否启用OB
|
71
|
+
self.logger.debug(f"{symbol} : BestFVGSMC策略 {ltf}|{htf} enable_FVG={enable_FVG} enable_OB={enable_OB} ...")
|
72
|
+
|
73
|
+
# 初始化HTF趋势相关变量
|
74
|
+
htf_last_side, htf_last_CHoCH_label = None, None
|
75
|
+
|
76
|
+
# 检查是否有上一个CHoCH结构
|
77
|
+
htf_last_CHoCH = self.htf_last_CHoCH.get(symbol,None)
|
78
|
+
|
79
|
+
# 如果存在上一个CHoCH结构,更新趋势标签和方向
|
80
|
+
if htf_last_CHoCH:
|
81
|
+
htf_last_CHoCH_label = htf_last_CHoCH["struct"]
|
82
|
+
htf_last_side = htf_last_CHoCH["side"]
|
83
|
+
|
84
|
+
|
85
|
+
# 1. HTF 判断struct趋势(CHoCH\SMS\BMS) ,HTF struct 看趋势,CTF 看FVG和OB的位置
|
86
|
+
swing_points_length = smc_strategy.get('swing_points_length',10)
|
87
|
+
htf_struct = self.detect_struct(htf_df,prd=swing_points_length,struct_key="CHoCH")
|
88
|
+
htf_struct_label = htf_struct["struct"]
|
89
|
+
htf_last_pivot_high = htf_struct["pivot_high"]
|
90
|
+
htf_last_pivot_low = htf_struct["pivot_low"]
|
91
|
+
htf_last_mid_line = self.calculate_ce(symbol,htf_last_pivot_high,htf_last_pivot_low)
|
92
|
+
|
93
|
+
|
94
|
+
# 检查是否已形成CHoCH结构
|
95
|
+
if not (htf_last_CHoCH or 'CHoCH' in htf_struct_label):
|
96
|
+
self.logger.debug(f"{symbol} : {htf} 未形成 CHoCH struct,不下单。{htf_struct}。")
|
97
|
+
return
|
98
|
+
|
99
|
+
# 更新最新的CHoCH结构信息
|
100
|
+
if 'CHoCH' in htf_struct_label and htf_struct_label != htf_last_CHoCH_label:
|
101
|
+
self.htf_last_CHoCH[symbol] = htf_struct
|
102
|
+
htf_last_CHoCH = htf_struct
|
103
|
+
htf_last_CHoCH_label = htf_struct_label
|
104
|
+
htf_last_side = htf_struct["side"]
|
105
|
+
|
106
|
+
|
107
|
+
# 2. HTF 获取最新的两个极值点,设置折价(discount)区和溢价(premium)区
|
108
|
+
|
109
|
+
|
110
|
+
# 计算溢价和折价区
|
111
|
+
premium_box = {
|
112
|
+
'top': htf_last_pivot_high,
|
113
|
+
'bot': htf_last_mid_line,
|
114
|
+
'ce': self.calculate_ce(symbol,htf_last_pivot_high,htf_last_mid_line)
|
115
|
+
}
|
116
|
+
discount_box = {
|
117
|
+
'top': htf_last_mid_line,
|
118
|
+
'bot': htf_last_pivot_low,
|
119
|
+
'ce': self.calculate_ce(symbol,htf_last_mid_line,htf_last_pivot_low)
|
120
|
+
}
|
121
|
+
|
122
|
+
self.logger.info(f"{symbol} : {htf} 趋势={htf_last_CHoCH_label}")
|
123
|
+
self.logger.debug(f"{symbol} : \npivot_high={htf_last_pivot_high} pivot_low={htf_last_pivot_low} mid_line={htf_last_mid_line}\n溢价区={premium_box}\n折价区={discount_box}")
|
124
|
+
|
125
|
+
# 3. find HTF FVG
|
126
|
+
pivot_index = htf_struct["pivot_low_index"] if htf_last_side == "buy" else htf_struct["pivot_high_index"]
|
127
|
+
htf_fvg_boxes = self.find_fvg_boxes(htf_df,side=htf_last_side,threshold=htf_last_mid_line,check_balanced=False,pivot_index=pivot_index)
|
128
|
+
if len(htf_fvg_boxes) == 0:
|
129
|
+
self.logger.debug(f"{symbol} : HTF={htf} 方向={htf_last_side}, 未找到 FVG")
|
130
|
+
return
|
131
|
+
self.logger.debug(f"{symbol} : HTF_fvg_box={htf_fvg_boxes[-1]}")
|
132
|
+
|
133
|
+
# 判断是否进入最近的FVG
|
134
|
+
if_tap_into_fvg = self.check_price_in_fvg(htf_df,htf_last_side,htf_fvg_boxes[-1])
|
135
|
+
if not if_tap_into_fvg:
|
136
|
+
self.logger.debug(f"{symbol} : 价格[未进入]HTF_FVG区域,不进行下单")
|
137
|
+
return
|
138
|
+
else:
|
139
|
+
self.logger.debug(f"{symbol} : 价格[进入]HTF_FVG区域,开始下单。fvgbox={htf_fvg_boxes[-1]}")
|
140
|
+
|
141
|
+
# 4. LTF 判断struct趋势是否有CHoCH
|
142
|
+
|
143
|
+
|
144
|
+
ltf_kLines = self.get_historical_klines(symbol=symbol, bar=ltf)
|
145
|
+
ltf_df = self.format_klines(ltf_kLines)
|
146
|
+
|
147
|
+
ltf_struct = self.detect_struct(ltf_df,prd=swing_points_length)
|
148
|
+
ltf_struct_label = ltf_struct["struct"]
|
149
|
+
ltf_struct_side = ltf_struct["side"]
|
150
|
+
ltf_last_pivot_high = ltf_struct["pivot_high"]
|
151
|
+
ltf_last_pivot_low = ltf_struct["pivot_low"]
|
152
|
+
ltf_last_mid_line = self.calculate_ce(symbol,ltf_last_pivot_high,ltf_last_pivot_low)
|
153
|
+
|
154
|
+
# 计算溢价和折价区
|
155
|
+
ltf_premium_box = {
|
156
|
+
'top': ltf_last_pivot_high,
|
157
|
+
'bot': ltf_last_mid_line,
|
158
|
+
'ce': self.calculate_ce(symbol,ltf_last_pivot_high,ltf_last_mid_line)
|
159
|
+
}
|
160
|
+
ltf_discount_box = {
|
161
|
+
'top': ltf_last_mid_line,
|
162
|
+
'bot': ltf_last_pivot_low,
|
163
|
+
'ce': self.calculate_ce(symbol,ltf_last_mid_line,ltf_last_pivot_low)
|
164
|
+
}
|
165
|
+
|
166
|
+
self.logger.info(f"{symbol} : {ltf} 趋势={ltf_struct_label} struct={ltf_struct}")
|
167
|
+
self.logger.debug(f"{symbol} : \npivot_high={ltf_last_pivot_high} pivot_low={ltf_last_pivot_low} mid_line={ltf_last_mid_line}\n溢价区={ltf_premium_box}\n折价区={ltf_discount_box}")
|
168
|
+
|
169
|
+
|
170
|
+
# 5. LTF 寻找FVG,下单
|
171
|
+
# if htf_last_CHoCH_label != ltf_struct_label :
|
172
|
+
if htf_last_side != ltf_struct_side :
|
173
|
+
self.logger.debug(f"{symbol} : {htf} {htf_last_CHoCH_label} VS {ltf} {ltf_struct_label} 趋势不一致,不进行下单")
|
174
|
+
return
|
175
|
+
|
176
|
+
threshold = 0.0
|
177
|
+
# 如果LTF结构是BMS,趋势强,FVG的范围不要求,只要能接上就行,如果结构是CHoCH或SMS,趋势弱,则取折价区或溢价区的FVG
|
178
|
+
if 'BMS' in ltf_struct_label:
|
179
|
+
threshold = ltf_last_pivot_high if ltf_struct_side == "buy" else ltf_last_pivot_low
|
180
|
+
else:
|
181
|
+
threshold = self.calculate_ce(symbol,ltf_last_pivot_high,ltf_last_pivot_low)
|
182
|
+
|
183
|
+
pivot_index = ltf_struct["pivot_low_index"] if ltf_struct_side == "buy" else ltf_struct["pivot_high_index"]
|
184
|
+
|
185
|
+
ltf_fvg_boxes = self.find_fvg_boxes(ltf_df,side=ltf_struct_side,threshold=threshold,pivot_index=pivot_index)
|
186
|
+
|
187
|
+
if len(ltf_fvg_boxes) == 0:
|
188
|
+
self.logger.debug(f"{symbol} : LTF={ltf} 趋势={ltf_struct_label}, 未找到 FVG")
|
189
|
+
return
|
190
|
+
|
191
|
+
self.logger.debug(f"{symbol} : LTF_fvg_box={ltf_fvg_boxes[-1]}")
|
192
|
+
|
193
|
+
|
194
|
+
# 4. LTF 寻找FVG,下单
|
195
|
+
order_price = ltf_fvg_boxes[-1]["top"] if ltf_struct_side == "buy" else ltf_fvg_boxes[-1]["bot"]
|
196
|
+
|
197
|
+
latest_order_price = self.place_order_prices.get(symbol,0.0)
|
198
|
+
if order_price == latest_order_price:
|
199
|
+
self.logger.debug(f"{symbol} : 下单价格 {order_price} 未变化,不进行下单。")
|
200
|
+
return
|
201
|
+
|
202
|
+
|
203
|
+
# 下单
|
204
|
+
self.cancel_all_orders(symbol=symbol)
|
205
|
+
self.place_order(symbol=symbol, price=order_price, side=ltf_struct_side, pair_config=pair_config)
|
206
|
+
self.place_order_prices[symbol] = order_price # 记录下单价格,过滤重复下单
|
207
|
+
self.logger.debug(f"{symbol} : {ltf_struct_side}, 下单价格 {order_price}")
|
208
|
+
|
209
|
+
|
210
|
+
except KeyboardInterrupt:
|
211
|
+
self.logger.info("程序收到中断信号,开始退出...")
|
212
|
+
except Exception as e:
|
213
|
+
error_message = f"程序异常退出: {str(e)}"
|
214
|
+
self.logger.error(error_message,exc_info=True)
|
215
|
+
traceback.print_exc()
|
216
|
+
self.send_feishu_notification(error_message)
|
217
|
+
finally:
|
218
|
+
self.logger.info("-" * 60)
|
219
|
+
|
220
|
+
|
maker/SMCStrategyMaker.py
CHANGED
@@ -106,13 +106,22 @@ class SMCStrategyMaker(ThreeLineStrategyMaker):
|
|
106
106
|
return OB_boxes
|
107
107
|
|
108
108
|
|
109
|
-
def find_fvg_boxes(self, data, side, threshold, pivot_index=0, symbol=None, pair_config=None) -> list:
|
109
|
+
def find_fvg_boxes(self, data, side, threshold, check_balanced=True, pivot_index=0, symbol=None, pair_config=None) -> list:
|
110
110
|
"""_summary_
|
111
111
|
寻找公允价值缺口
|
112
112
|
Args:
|
113
|
-
|
114
|
-
side (_type_):
|
115
|
-
threshold (_type_):
|
113
|
+
data (_type_): K线数据
|
114
|
+
side (_type_): 交易方向 'buy'|'sell'
|
115
|
+
threshold (_type_): 阈值价格,通常为溢价和折价区的CE
|
116
|
+
check_balanced (bool): 是否检查FVG是否被平衡过,默认为True
|
117
|
+
pivot_index (int): 枢轴点索引,默认为0
|
118
|
+
symbol (_type_): 交易对名称
|
119
|
+
pair_config (_type_): 交易对配置
|
120
|
+
Returns:
|
121
|
+
list: FVG盒子列表,每个盒子包含以下字段:
|
122
|
+
# index: FVG出现的K线位置索引
|
123
|
+
# top: FVG的上边界价格,对应K线的最高价或最低价
|
124
|
+
# bot: FVG的下边界价格,对应K线的最高价或最低价
|
116
125
|
"""
|
117
126
|
|
118
127
|
df = data.copy().iloc[pivot_index:]
|
@@ -132,13 +141,13 @@ class SMCStrategyMaker(ThreeLineStrategyMaker):
|
|
132
141
|
fvg_boxes = [
|
133
142
|
{
|
134
143
|
'index': idx - 2, # FVG的索引
|
135
|
-
'top': float(df.loc[idx - 1, 'low']), # FVG高点为右1K线的最低点
|
144
|
+
'top': min(float(df.loc[idx - 1, 'low']),threshold), # FVG高点为右1K线的最低点
|
136
145
|
'bot': float(df.loc[idx - 3, 'high']) # FVG低点为左1K线的最高点
|
137
146
|
}
|
138
147
|
# [df.loc[idx - 1, 'low'], df.loc[idx - 3, 'high'], idx - 2]
|
139
148
|
for idx in valid_indices
|
140
149
|
if df.loc[idx - 3, 'high'] <= threshold and
|
141
|
-
all((df.loc[idx:, 'low']
|
150
|
+
(not check_balanced or all((df.loc[idx:, 'low'] > df.loc[idx - 3, 'high']))) # check_balanced = true 检查FVG是否被平衡过
|
142
151
|
]
|
143
152
|
|
144
153
|
|
@@ -157,31 +166,44 @@ class SMCStrategyMaker(ThreeLineStrategyMaker):
|
|
157
166
|
fvg_boxes = [
|
158
167
|
{
|
159
168
|
'index': idx - 2, # FVG的索引
|
160
|
-
'top': float(df.loc[idx -
|
161
|
-
'bot': float(df.loc[idx -
|
169
|
+
'top': float(df.loc[idx - 3, 'low']), # FVG高点为右1K线的最高点
|
170
|
+
'bot': max(float(df.loc[idx - 1, 'high']),threshold) # FVG低点为左1K线的最低点
|
162
171
|
}
|
163
172
|
|
164
173
|
for idx in valid_indices
|
165
174
|
if df.loc[idx - 3, 'low'] >= threshold and
|
166
|
-
all((df.loc[idx:, 'high']
|
175
|
+
(not check_balanced or all((df.loc[idx:, 'high'] < df.loc[idx - 3, 'low']))) # check_balanced = true 检查FVG是否被平衡过
|
167
176
|
]
|
168
177
|
|
169
178
|
|
170
179
|
return fvg_boxes
|
171
180
|
|
172
181
|
|
173
|
-
def detect_struct(self, data, prd=10, s1=True, resp=7) -> dict:
|
182
|
+
def detect_struct(self, data, prd=10, struct_key=None, check_bounds=True, global_extremum=False, s1=True, resp=7) -> dict:
|
174
183
|
"""_summary_
|
175
|
-
|
176
|
-
|
177
|
-
:
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
184
|
+
识别SMC结构,参考 Tradingview Smart Money Concepts Probability (Expo)@Openfund
|
185
|
+
|
186
|
+
Args:
|
187
|
+
data (df): df格式的K线数据
|
188
|
+
prd (int): 计算Swing Points的bar数量
|
189
|
+
struct_key (str): 结构类型,如 'CHoCH'|'SMS'|'BMS'
|
190
|
+
check_bounds (bool): 计算Swing Points是否检查边界,默认为True
|
191
|
+
global_extremum (bool): 是否使用全局极值点,默认为False
|
192
|
+
s1 (bool): 结构响应布尔值
|
193
|
+
resp (int): 响应周期
|
194
|
+
Returns:
|
195
|
+
dict: 包含结构识别结果的字典,包含以下字段:
|
196
|
+
"struct": 结构类型,如 'Bullish_CHoCH'|'Bullish_SMS'|'Bullish_BMS'|'Bearish_CHoCH'|'Bearish_SMS'|'Bearish_BMS'
|
197
|
+
"index": 结构出现的位置索引
|
198
|
+
"pivot_high": 枢轴高点价格
|
199
|
+
"pivot_high_index": 枢轴高点索引
|
200
|
+
"pivot_low": 枢轴低点价格
|
201
|
+
"pivot_low_index": 枢轴低点索引
|
202
|
+
"side": 交易方向,'buy'或'sell'
|
203
|
+
|
204
|
+
|
182
205
|
"""
|
183
|
-
|
184
|
-
|
206
|
+
|
185
207
|
# data = data.copy()
|
186
208
|
data['Up'] = None
|
187
209
|
data['Dn'] = None
|
@@ -204,8 +226,8 @@ class SMCStrategyMaker(ThreeLineStrategyMaker):
|
|
204
226
|
data.at[index, 'iDn'] = data.at[max(0,index - 1), 'iDn'] if data.at[max(0,index - 1), 'iDn'] is not None else index
|
205
227
|
|
206
228
|
# 寻找枢轴高点和低点
|
207
|
-
pvtHi = self.is_pivot_high(data, index, prd)
|
208
|
-
pvtLo = self.is_pivot_low(data, index, prd)
|
229
|
+
pvtHi = self.is_pivot_high(data, index, prd, check_bounds)
|
230
|
+
pvtLo = self.is_pivot_low(data, index, prd, check_bounds)
|
209
231
|
|
210
232
|
if pvtHi:
|
211
233
|
data.at[index, 'Up'] = data.at[index, 'high']
|
@@ -215,7 +237,8 @@ class SMCStrategyMaker(ThreeLineStrategyMaker):
|
|
215
237
|
data.at[index, 'iDn'] = index
|
216
238
|
# 寻找Bullish结构
|
217
239
|
if data.at[index, 'Up'] > data.at[index - 1, 'Up']:
|
218
|
-
|
240
|
+
|
241
|
+
data.at[index, 'iUp'] = index
|
219
242
|
if data.at[index - 1, 'pos'] <= 0:
|
220
243
|
# data.at[index, 'pattern'] = 'CHoCH (Bullish)'
|
221
244
|
data.at[index, 'pattern'] = 'Bullish_CHoCH'
|
@@ -230,12 +253,12 @@ class SMCStrategyMaker(ThreeLineStrategyMaker):
|
|
230
253
|
data.at[index, 'pattern'] = 'Bullish_BMS'
|
231
254
|
data.at[index, 'pos'] = data.at[index - 1, 'pos'] + 1
|
232
255
|
|
233
|
-
elif data.at[index, 'Up'] < data.at[index - 1, 'Up']:
|
256
|
+
elif global_extremum and data.at[index, 'Up'] < data.at[index - 1, 'Up']:
|
234
257
|
data.at[index, 'iUp'] = data.at[index - 1, 'iUp']
|
235
258
|
|
236
259
|
# # 寻找Bearish结构
|
237
260
|
if data.at[index, 'Dn'] < data.at[index - 1, 'Dn']:
|
238
|
-
|
261
|
+
data.at[index, 'iDn'] = index
|
239
262
|
if data.at[index - 1, 'pos'] >= 0:
|
240
263
|
|
241
264
|
data.at[index, 'pattern'] = 'Bearish_CHoCH'
|
@@ -249,7 +272,7 @@ class SMCStrategyMaker(ThreeLineStrategyMaker):
|
|
249
272
|
data.at[index, 'pattern'] = 'Bearish_BMS'
|
250
273
|
data.at[index, 'pos'] = data.at[index - 1, 'pos'] - 1
|
251
274
|
|
252
|
-
elif data.at[index, 'Dn'] > data.at[index - 1, 'Dn']:
|
275
|
+
elif global_extremum and data.at[index, 'Dn'] > data.at[index - 1, 'Dn']:
|
253
276
|
data.at[index, 'iDn'] = data.at[index - 1, 'iDn']
|
254
277
|
|
255
278
|
# 获取最后一个结构和位置
|
@@ -267,6 +290,8 @@ class SMCStrategyMaker(ThreeLineStrategyMaker):
|
|
267
290
|
|
268
291
|
for i in range(len(data)-1, -1, -1):
|
269
292
|
if data.at[i, 'pattern'] is not None:
|
293
|
+
if struct_key is not None and struct_key not in data.at[i, 'pattern']:
|
294
|
+
continue
|
270
295
|
last_struct["struct"] = data.at[i, 'pattern']
|
271
296
|
last_struct["index"] = i
|
272
297
|
|
@@ -298,7 +323,7 @@ class SMCStrategyMaker(ThreeLineStrategyMaker):
|
|
298
323
|
|
299
324
|
|
300
325
|
|
301
|
-
def is_pivot_high(self,data, index, period, check_bounds=False):
|
326
|
+
def is_pivot_high(self, data, index, period, check_bounds=False):
|
302
327
|
"""
|
303
328
|
判断当前索引处是否为枢轴高点
|
304
329
|
:param data: 包含 'high' 列的 DataFrame
|
@@ -314,7 +339,7 @@ class SMCStrategyMaker(ThreeLineStrategyMaker):
|
|
314
339
|
return all(current_high >= prev_highs) and all(current_high >= next_highs)
|
315
340
|
|
316
341
|
|
317
|
-
def is_pivot_low(self,data, index, period, check_bounds=False):
|
342
|
+
def is_pivot_low(self, data, index, period, check_bounds=False):
|
318
343
|
"""
|
319
344
|
判断当前索引处是否为枢轴低点
|
320
345
|
:param data: 包含 'low' 列的 DataFrame
|
@@ -369,7 +394,7 @@ class SMCStrategyMaker(ThreeLineStrategyMaker):
|
|
369
394
|
|
370
395
|
enable_FVG = smc_strategy.get('enable_FVG',True) # 是否启用FVG
|
371
396
|
enable_OB = smc_strategy.get('enable_OB',True) # 是否启用OB
|
372
|
-
self.logger.debug(f"{symbol} : SMC策略 {ctf}
|
397
|
+
self.logger.debug(f"{symbol} : SMC策略 {ctf}|{htf} enable_FVG={enable_FVG} enable_OB={enable_OB} ...")
|
373
398
|
|
374
399
|
side = 'none'
|
375
400
|
# 1. HTF 判断struct趋势(CHoCH\SMS\BMS) ,HTF struct 看趋势,CTF 看FVG和OB的位置
|
maker/main.py
CHANGED
@@ -9,6 +9,7 @@ from maker.WickReversalStrategyMaker import WickReversalStrategyMaker
|
|
9
9
|
from maker.ThreeLineStrategyMaker import ThreeLineStrategyMaker
|
10
10
|
from maker.MACDStrategyMaker import MACDStrategyMaker
|
11
11
|
from maker.SMCStrategyMaker import SMCStrategyMaker
|
12
|
+
from maker.BestFVGStrategyMaker import BestFVGStrategyMaker
|
12
13
|
|
13
14
|
def build_logger(log_config) -> logging.Logger:
|
14
15
|
# 配置日志
|
@@ -59,9 +60,16 @@ def main():
|
|
59
60
|
feishu_webhook_url = config_data['feishu_webhook']
|
60
61
|
logger = build_logger(config_data["Logger"])
|
61
62
|
package_name = __package__ or "maker"
|
62
|
-
|
63
|
-
|
64
|
-
|
63
|
+
|
64
|
+
|
65
|
+
maker = config_data.get('actived_maker', 'MACDStrategyMaker')
|
66
|
+
|
67
|
+
|
68
|
+
# 根据配置动态创建策略实例
|
69
|
+
strategy_class = globals()[maker]
|
70
|
+
bot = strategy_class(config_data, platform_config, feishu_webhook=feishu_webhook_url, logger=logger)
|
71
|
+
|
72
|
+
logger.info(f" ++ {package_name}.{maker}:{version} is doing...")
|
65
73
|
|
66
74
|
# 获取计划配置
|
67
75
|
schedule_config = config_data.get('schedule', {})
|
@@ -93,7 +101,7 @@ def main():
|
|
93
101
|
)
|
94
102
|
|
95
103
|
try:
|
96
|
-
logger.info(f"启动定时任务调度器,从 {next_run} 开始每
|
104
|
+
logger.info(f"启动定时任务调度器,从 {next_run} 开始每{monitor_interval}分钟执行一次...")
|
97
105
|
scheduler.start()
|
98
106
|
except (KeyboardInterrupt, SystemExit):
|
99
107
|
logger.info("程序收到中断信号,正在退出...")
|
@@ -1,15 +1,16 @@
|
|
1
|
+
maker/BestFVGStrategyMaker.py,sha256=IEE8jEIYcpS0jD5jbBx0Tqhy5vFRdcZJ3WUnsUCIH88,10384
|
1
2
|
maker/MACDStrategyMaker.py,sha256=iS5HO04piKHFJxUI2e5QmicxzGeK-V1aphJSr2n_4Ac,12651
|
2
|
-
maker/SMCStrategyMaker.py,sha256=
|
3
|
+
maker/SMCStrategyMaker.py,sha256=LUm9HFX5S_OKesynPyf4SBsfGnK0awPeChpHWOfD8VM,26957
|
3
4
|
maker/ThreeLineStrategyMaker.py,sha256=ArjnHlGECiD3cCFXxO0Ex5scR2agwoxZY-4mKukyKc4,30402
|
4
5
|
maker/WickReversalStrategyMaker.py,sha256=7DqPDVJot4EM0_lSAcFAHrR9rNvkIds9KLMoDOiAHEc,17486
|
5
6
|
maker/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
6
7
|
maker/config.py,sha256=YPxghO5i0vgRg9Cja8kGj9O7pgSbbtzOgf3RexqXXwY,1188
|
7
|
-
maker/main.py,sha256=
|
8
|
+
maker/main.py,sha256=XpZ2N55bi5Fi_r2FKuqBu8e71mTxgHgrtzJUjBe1fUc,4405
|
8
9
|
maker/main_m.py,sha256=0PzDTnuBrxfpy5WDfsIHKAzZ_7pkuvuqqeWik0vpWio,15522
|
9
10
|
maker/okxapi.py,sha256=_9G0U_o0ZC8NxaT6PqpiLgxBm9gPobC9PsFHZE1c5w0,553
|
10
11
|
maker/zhen.py.bak,sha256=HNkrQbJts8G9umE9chEFsc0cLQApcM9KOVNMYPpkBXM,10918
|
11
12
|
maker/zhen_2.py,sha256=4IaHVtTCMSlrLGSTZrWpW2q-f7HZsUNRkW_-5QgWv24,10509
|
12
|
-
openfund_maker-2.0.
|
13
|
-
openfund_maker-2.0.
|
14
|
-
openfund_maker-2.0.
|
15
|
-
openfund_maker-2.0.
|
13
|
+
openfund_maker-2.0.2.dist-info/METADATA,sha256=6_GxwAKR7yNlXakwFH7Q7I0UiOrPTkuqLVJWZCjN8_M,1953
|
14
|
+
openfund_maker-2.0.2.dist-info/WHEEL,sha256=IYZQI976HJqqOpQU6PHkJ8fb3tMNBFjg-Cn-pwAbaFM,88
|
15
|
+
openfund_maker-2.0.2.dist-info/entry_points.txt,sha256=gKMytICEKcMRFQDFkHZLnIpID7UQFoTIM_xcpiiV6Ns,50
|
16
|
+
openfund_maker-2.0.2.dist-info/RECORD,,
|
File without changes
|
File without changes
|