openfund-taker 1.0.16__py3-none-any.whl → 1.1.0__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.
- {openfund_taker-1.0.16.dist-info → openfund_taker-1.1.0.dist-info}/METADATA +1 -1
- {openfund_taker-1.0.16.dist-info → openfund_taker-1.1.0.dist-info}/RECORD +5 -5
- taker/MultiAssetNewTradingBot.py +69 -53
- {openfund_taker-1.0.16.dist-info → openfund_taker-1.1.0.dist-info}/WHEEL +0 -0
- {openfund_taker-1.0.16.dist-info → openfund_taker-1.1.0.dist-info}/entry_points.txt +0 -0
@@ -1,4 +1,4 @@
|
|
1
|
-
taker/MultiAssetNewTradingBot.py,sha256=
|
1
|
+
taker/MultiAssetNewTradingBot.py,sha256=GTuzCyI1SfCez-G1tI_B-pINLOPcJtcOqTrQiBPcWGo,35952
|
2
2
|
taker/MultiAssetOldTradingBot.py,sha256=uBh_BxglvcbaHIsWHM7GI9Qa_QjzsxXaXJAAWEOMO5c,15315
|
3
3
|
taker/ThreeLineTradingBot.py,sha256=oXIoQ8z9AzKzk0z13d0ufj2KGBOk5iHJTJNZQRDKA5U,20625
|
4
4
|
taker/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -9,7 +9,7 @@ taker/chua_ok_all.py,sha256=2XnZM6QdB3juSE1pqQIJyh2x1XuhlTlnBKNA3owlJ9E,15267
|
|
9
9
|
taker/chua_ok_bot.py,sha256=9SW0ujhi6PfN4yR1JZ9NaA37HtnXJ2QAWUfW52NG68w,13109
|
10
10
|
taker/config.py,sha256=YPxghO5i0vgRg9Cja8kGj9O7pgSbbtzOgf3RexqXXwY,1188
|
11
11
|
taker/main.py,sha256=8cLWzEvQDeELbY5Av7JqkEyYbaNqSbAbVl1tQHXzU8s,1954
|
12
|
-
openfund_taker-1.0.
|
13
|
-
openfund_taker-1.0.
|
14
|
-
openfund_taker-1.0.
|
15
|
-
openfund_taker-1.0.
|
12
|
+
openfund_taker-1.1.0.dist-info/METADATA,sha256=LVhdFLOtAZJ9Kp9P2IdbmUsrx4q0sUbIkif7oOhMeyc,7502
|
13
|
+
openfund_taker-1.1.0.dist-info/WHEEL,sha256=IYZQI976HJqqOpQU6PHkJ8fb3tMNBFjg-Cn-pwAbaFM,88
|
14
|
+
openfund_taker-1.1.0.dist-info/entry_points.txt,sha256=a7mG8F7aOA5-Gk2vPWuAR4537faxaHUgM_jwIDBZoEc,50
|
15
|
+
openfund_taker-1.1.0.dist-info/RECORD,,
|
taker/MultiAssetNewTradingBot.py
CHANGED
@@ -81,9 +81,9 @@ class MultiAssetNewTradingBot:
|
|
81
81
|
payload = {"msg_type": "text", "content": {"text": message}}
|
82
82
|
response = requests.post(self.feishu_webhook, json=payload, headers=headers)
|
83
83
|
if response.status_code == 200:
|
84
|
-
self.logger.
|
84
|
+
self.logger.debug("飞书通知发送成功")
|
85
85
|
else:
|
86
|
-
self.logger.
|
86
|
+
self.logger.warn("飞书通知发送失败,状态码: %s", response.status_code)
|
87
87
|
except Exception as e:
|
88
88
|
self.logger.error("发送飞书通知时出现异常: %s", str(e))
|
89
89
|
|
@@ -117,7 +117,7 @@ class MultiAssetNewTradingBot:
|
|
117
117
|
else:
|
118
118
|
raise ValueError("Unexpected response structure or missing candlestick data")
|
119
119
|
|
120
|
-
def judge_cross_direction(self,fastklines,slowklines) :
|
120
|
+
def judge_cross_direction(self,symbol, fastklines ,slowklines) :
|
121
121
|
# 创建DataFrame
|
122
122
|
df = pd.DataFrame({
|
123
123
|
'fast': fastklines,
|
@@ -131,7 +131,9 @@ class MultiAssetNewTradingBot:
|
|
131
131
|
# 从后往前找最近的交叉点
|
132
132
|
last_golden = df['golden_cross'].iloc[::-1].idxmax() if df['golden_cross'].any() else None
|
133
133
|
last_death = df['death_cross'].iloc[::-1].idxmax() if df['death_cross'].any() else None
|
134
|
+
# self.logger.debug(f"golden_cross = {last_golden}, death_cross = {last_death}")
|
134
135
|
|
136
|
+
# self.logger.debug(f"df= \n{df[['fast','slow','golden_cross','death_cross']].tail()}")
|
135
137
|
# 判断最近的交叉类型
|
136
138
|
if last_golden is None and last_death is None:
|
137
139
|
return {
|
@@ -152,29 +154,53 @@ class MultiAssetNewTradingBot:
|
|
152
154
|
'index': last_death
|
153
155
|
}
|
154
156
|
|
157
|
+
def judge_ma_apex(self,symbol,pair_config, fastklines,slowklines) -> bool:
|
158
|
+
period = int(pair_config.get('ema_range_period', 3))
|
159
|
+
precision= self.get_precision_length(symbol)
|
155
160
|
|
156
|
-
def judge_ma_apex(self,symbol, fastklines,slowklines) -> bool:
|
157
161
|
df = pd.DataFrame({
|
158
162
|
'ema': fastklines,
|
159
163
|
'sma': slowklines
|
160
164
|
})
|
161
|
-
|
162
165
|
# 快线和慢线的差值
|
163
|
-
|
166
|
+
# 将ema和sma转换为tick_size精度
|
167
|
+
# df['diff'] = df['ema'].apply(lambda x: float(self.round_price_to_tick(x, tick_size))) - df['sma'].apply(lambda x: float(self.round_price_to_tick(x, tick_size)))
|
168
|
+
df['diff'] = df['ema'].round(precision)-df['sma'].round(precision)
|
169
|
+
df['ema_diff'] = df['ema'] - df['ema'].shift(1)
|
170
|
+
df['sma_diff'] = df['sma'] - df['sma'].shift(1)
|
164
171
|
# 计算斜率,【正】表示两线距离扩张,【负】表示两线距离收缩
|
165
172
|
df['slope'] = df['diff'].abs().diff().round(4)
|
166
|
-
df['flag'] = df['slope'] <= 0.0
|
167
173
|
|
168
|
-
self.logger.debug(f"{symbol}: slopes = \n{df[['ema','sma','
|
169
|
-
|
170
|
-
#
|
171
|
-
|
172
|
-
|
174
|
+
self.logger.debug(f"{symbol}: slopes = \n{df[['ema','ema_diff','sma','sma_diff','diff','slope']].iloc[-6:-1]} ")
|
175
|
+
|
176
|
+
# 两条线的距离是扩张状态还是收缩状态 true 是收缩 flase 是扩张
|
177
|
+
is_expanding_or_contracting = all(df['slope'].tail(period) <= 0 ) and any(df['slope'].tail(period) < 0)
|
178
|
+
|
179
|
+
return is_expanding_or_contracting
|
173
180
|
|
174
181
|
# 定义根据均线斜率判断 K 线方向的函数: 0 空 1 多 -1 平
|
175
182
|
|
183
|
+
def judge_range_diff(self,symbol,pair_config,prices:pd.Series) -> bool:
|
184
|
+
"""
|
185
|
+
计算价格列表中最后一个价格与第一个价格的差值。
|
186
|
+
Args:
|
187
|
+
prices: 价格列表。
|
188
|
+
Returns:
|
189
|
+
diff: 计算最高价列的最大值与最小值的差值
|
190
|
+
。
|
191
|
+
"""
|
192
|
+
limit = int(pair_config.get('ema_range_limit', 1))
|
193
|
+
period = int(pair_config.get('ema_range_period', 3))
|
194
|
+
tick_size = self.get_tick_size(symbol)
|
195
|
+
if prices.empty:
|
196
|
+
return None
|
197
|
+
|
198
|
+
diff = prices.tail(period).max() - prices.tail(period).min()
|
199
|
+
self.logger.debug(f"{symbol}: 最高价列的最大值与最小值的差值 = {diff:.9f}")
|
200
|
+
return abs(diff) <= tick_size * limit
|
201
|
+
|
176
202
|
# 定义根据均线斜率判断 K 线方向的函数: 0 空 1 多 -1 平
|
177
|
-
def judge_k_line_direction(self,symbol, pair_config, ema:pd.Series) -> int:
|
203
|
+
def judge_k_line_direction(self, symbol, pair_config, ema: pd.Series, klines) -> int:
|
178
204
|
"""
|
179
205
|
判断K线方向
|
180
206
|
Args:
|
@@ -184,36 +210,22 @@ class MultiAssetNewTradingBot:
|
|
184
210
|
Returns:
|
185
211
|
int: -1:平, 0:空, 1:多
|
186
212
|
"""
|
187
|
-
def check_ema_range(ema_data: pd.Series, period: int, limit: float, tick_size: float) -> bool:
|
188
|
-
"""检查EMA是否在指定范围内震荡"""
|
189
|
-
ema_window = ema_data[-period:]
|
190
|
-
price_range = ema_window.max() - ema_window.min()
|
191
|
-
return abs(price_range) <= limit * tick_size
|
192
|
-
|
193
|
-
def get_trend_direction(slope: float) -> int:
|
194
|
-
"""根据斜率判断趋势方向"""
|
195
|
-
if slope > 0:
|
196
|
-
return 1 # 上升趋势
|
197
|
-
elif slope < 0:
|
198
|
-
return 0 # 下降趋势
|
199
|
-
return -1 # 震荡趋势
|
200
|
-
|
201
213
|
# 获取配置参数
|
202
|
-
|
203
|
-
ema_range_period = int(pair_config.get('ema_range_period', 3))
|
204
|
-
ema_range_limit = float(pair_config.get('ema_range_limit', 1))
|
214
|
+
period = int(pair_config.get('ema_range_period', 3))
|
205
215
|
|
206
|
-
|
207
|
-
|
208
|
-
|
216
|
+
ema_4_diff = ema.diff().tail(period)
|
217
|
+
|
218
|
+
direction = None
|
219
|
+
if all(ema_4_diff <= 0) :
|
220
|
+
# 下降趋势
|
221
|
+
direction = 0
|
222
|
+
elif all(ema_4_diff >= 0) :
|
223
|
+
# 上升趋势
|
224
|
+
direction = 1
|
209
225
|
else:
|
210
|
-
#
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
self.logger.debug(f"{symbol}: 极差={abs(ema[-ema_range_period:].max() - ema[-ema_range_period:].min()):.9f} "
|
215
|
-
f"斜率={ema.diff().iloc[-1]:.9f}, K线方向 {direction}")
|
216
|
-
|
226
|
+
# 震荡趋势
|
227
|
+
direction = -1
|
228
|
+
self.logger.debug(f"{symbol}: K线极差={ema_4_diff.map('{:.9f}'.format).values} ,K线方向={direction}")
|
217
229
|
return direction
|
218
230
|
|
219
231
|
def check_reverse_position(self,symbol,position,pair_config):
|
@@ -229,7 +241,8 @@ class MultiAssetNewTradingBot:
|
|
229
241
|
fastk = self.calculate_ema_pandas(symbol, klines, period=ema_length)
|
230
242
|
slowk = self.calculate_sma_pandas(symbol, klines, period=sma_length)
|
231
243
|
|
232
|
-
cross_direction = self.judge_cross_direction(fastklines=fastk,slowklines=slowk)
|
244
|
+
cross_direction = self.judge_cross_direction(symbol=symbol,fastklines=fastk,slowklines=slowk)
|
245
|
+
|
233
246
|
# 更新交叉状态
|
234
247
|
if cross_direction['cross'] != -1 : #本次不一定有交叉
|
235
248
|
self.cross_directions[symbol] = cross_direction
|
@@ -238,17 +251,20 @@ class MultiAssetNewTradingBot:
|
|
238
251
|
last_cross_direction = self.exchange.safe_dict(self.cross_directions,symbol,None)
|
239
252
|
# 计算 快线EMA & 慢线SMA
|
240
253
|
# 结合金叉死叉判断是否是周期顶部和底部
|
241
|
-
is_apex = self.judge_ma_apex(symbol=symbol,fastklines=fastk,slowklines=slowk)
|
254
|
+
is_apex = self.judge_ma_apex(symbol=symbol,pair_config=pair_config, fastklines=fastk,slowklines=slowk)
|
255
|
+
|
256
|
+
kline_direction = self.judge_k_line_direction(symbol=symbol, pair_config=pair_config, ema=fastk, klines=klines)
|
257
|
+
# if_inner_range = self.judge_range_diff(symbol=symbol, pair_config=pair_config, prices=fastk)
|
242
258
|
|
243
|
-
self.logger.debug(f"{symbol} cross={last_cross_direction}
|
244
|
-
# 金叉逻辑
|
245
|
-
if last_cross_direction and last_cross_direction['cross'] == 1 and is_apex and side == 'long':
|
246
|
-
self.logger.debug(f"{symbol} 金叉:{last_cross_direction['cross']}
|
259
|
+
self.logger.debug(f"{symbol} cross={last_cross_direction},两线收缩={is_apex},持仓方向={side}")
|
260
|
+
# 金叉逻辑 ,如果是金叉,且是周期顶部,且K线方向是空头,就清仓多单
|
261
|
+
if last_cross_direction and last_cross_direction['cross'] == 1 and is_apex and side == 'long' and kline_direction == 0:
|
262
|
+
self.logger.debug(f"{symbol} 金叉:{last_cross_direction['cross']},两线收缩={is_apex},持仓方向={side} ,开始清理多单!!")
|
247
263
|
self.close_all_positions(symbol=symbol, position=position)
|
248
264
|
|
249
|
-
# 死叉逻辑
|
250
|
-
elif last_cross_direction and last_cross_direction['cross'] == 0 and is_apex and side == 'short':
|
251
|
-
self.logger.debug(f"{symbol} 死叉:{last_cross_direction['cross']}
|
265
|
+
# 死叉逻辑 ,如果是死叉,且是周期底部,且K线方向是多头,就清仓空单
|
266
|
+
elif last_cross_direction and last_cross_direction['cross'] == 0 and is_apex and side == 'short' and kline_direction == 1:
|
267
|
+
self.logger.debug(f"{symbol} 死叉:{last_cross_direction['cross']},两线收缩={is_apex},持仓方向={side} ,开始清理空单!!")
|
252
268
|
self.close_all_positions(symbol=symbol, position=position)
|
253
269
|
|
254
270
|
except KeyboardInterrupt:
|
@@ -266,9 +282,9 @@ class MultiAssetNewTradingBot:
|
|
266
282
|
:param period: SMA 周期
|
267
283
|
:return: SMA 值
|
268
284
|
"""
|
269
|
-
|
285
|
+
|
270
286
|
df = pd.DataFrame(kLines, columns=['timestamp', 'open', 'high', 'low', 'close', 'volume'])
|
271
|
-
sma = df['close'].rolling(window=period).mean()
|
287
|
+
sma = df['close'].rolling(window=period).mean()
|
272
288
|
return sma
|
273
289
|
|
274
290
|
def calculate_ema_pandas(self,symbol,kLines, period):
|
@@ -278,10 +294,10 @@ class MultiAssetNewTradingBot:
|
|
278
294
|
:param period: EMA 周期
|
279
295
|
:return: EMA 值
|
280
296
|
"""
|
281
|
-
|
297
|
+
|
282
298
|
df = pd.DataFrame(kLines, columns=['timestamp', 'open', 'high', 'low', 'close', 'volume'])
|
283
299
|
# 计算EMA
|
284
|
-
ema = df['close'].ewm(span=period, adjust=False).mean()
|
300
|
+
ema = df['close'].ewm(span=period, adjust=False).mean()
|
285
301
|
return ema
|
286
302
|
|
287
303
|
# 计算平均利润
|
File without changes
|
File without changes
|