gfrdegdergr
This commit is contained in:
@@ -1 +1,5 @@
|
|||||||
print(10000 * 0.001)
|
print(4000 * 1.001)
|
||||||
|
print(3954.11 * 1.002)
|
||||||
|
print(4000 * 0.998)
|
||||||
|
print(4000 * 0.998)
|
||||||
|
print(4000 * 0.998)
|
||||||
|
|||||||
154
回测数据/通过止盈止损策略.py
154
回测数据/通过止盈止损策略.py
@@ -2,6 +2,7 @@ import datetime
|
|||||||
import requests
|
import requests
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
|
|
||||||
|
# 请求头(模拟浏览器请求,避免被拒绝)
|
||||||
headers = {
|
headers = {
|
||||||
'accept': 'application/json, text/plain, */*',
|
'accept': 'application/json, text/plain, */*',
|
||||||
'accept-language': 'zh,zh-CN;q=0.9,zh-HK;q=0.8,en;q=0.7',
|
'accept-language': 'zh,zh-CN;q=0.9,zh-HK;q=0.8,en;q=0.7',
|
||||||
@@ -21,67 +22,133 @@ headers = {
|
|||||||
|
|
||||||
|
|
||||||
def fetch_kline(day: int):
|
def fetch_kline(day: int):
|
||||||
"""获取某一天的分钟K线数据"""
|
"""
|
||||||
|
获取某一天的分钟K线数据
|
||||||
|
:param day: 日期中的“日”,比如27表示2025-09-27
|
||||||
|
:return: 按时间顺序排序后的K线数据
|
||||||
|
"""
|
||||||
time_ser = datetime.datetime(2025, 9, day)
|
time_ser = datetime.datetime(2025, 9, day)
|
||||||
|
|
||||||
|
# 当天 0点
|
||||||
start_of_day = time_ser.replace(hour=0, minute=0, second=0, microsecond=0)
|
start_of_day = time_ser.replace(hour=0, minute=0, second=0, microsecond=0)
|
||||||
|
# 当天 23:59:59
|
||||||
end_of_day = time_ser.replace(hour=23, minute=59, second=59, microsecond=0)
|
end_of_day = time_ser.replace(hour=23, minute=59, second=59, microsecond=0)
|
||||||
|
|
||||||
|
# API 参数
|
||||||
params = {
|
params = {
|
||||||
'symbol': 'ETH-USDT',
|
'symbol': 'ETH-USDT', # 交易对
|
||||||
'period': '1min',
|
'period': '1min', # 1分钟K线
|
||||||
'start': int(start_of_day.timestamp()),
|
'start': int(start_of_day.timestamp()), # 开始时间戳
|
||||||
'end': int(end_of_day.timestamp()),
|
'end': int(end_of_day.timestamp()), # 结束时间戳
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# 请求接口
|
||||||
response = requests.get('https://capi.websea.com/webApi/market/getKline', params=params, headers=headers)
|
response = requests.get('https://capi.websea.com/webApi/market/getKline', params=params, headers=headers)
|
||||||
data = response.json()['result']['data']
|
data = response.json()['result']['data']
|
||||||
|
|
||||||
|
# 返回按 id(时间) 排序的列表
|
||||||
return sorted(data, key=lambda x: x['id'])
|
return sorted(data, key=lambda x: x['id'])
|
||||||
|
|
||||||
|
|
||||||
def backtest_kline(sorted_data, day):
|
def backtest_kline(sorted_data, day):
|
||||||
"""执行回测逻辑"""
|
"""
|
||||||
signals = wins = 0
|
回测策略逻辑
|
||||||
lig_price = low_price = 0
|
规则:
|
||||||
all_trades = []
|
- 做多:连续两根阳线,第二根包住第一根
|
||||||
|
- 做空:连续两根阴线,第二根包住第一根
|
||||||
|
止盈止损:
|
||||||
|
- 多单:止盈+0.15%,止损-0.2%
|
||||||
|
- 空单:止盈-0.15%,止损+0.2%
|
||||||
|
"""
|
||||||
|
|
||||||
|
signals = wins = 0 # 统计信号总数、胜率
|
||||||
|
lig_price = low_price = 0 # 多单收益、空单收益
|
||||||
|
all_trades = [] # 存储所有交易详情
|
||||||
|
|
||||||
|
# 遍历 K 线,至少需要 3 根(前一根+当前+下一根开仓)
|
||||||
for idx in range(1, len(sorted_data) - 2):
|
for idx in range(1, len(sorted_data) - 2):
|
||||||
prev = sorted_data[idx - 1]
|
prev = sorted_data[idx - 1] # 前一根K线
|
||||||
curr = sorted_data[idx]
|
curr = sorted_data[idx] # 当前K线
|
||||||
entry_candle = sorted_data[idx + 1] # ✅ 下一根开仓
|
entry_candle = sorted_data[idx + 1] # 下一根K线,用于入场
|
||||||
|
|
||||||
prev_open, prev_close = float(prev['open']), float(prev['close'])
|
prev_open, prev_close = float(prev['open']), float(prev['close'])
|
||||||
curr_open, curr_close = float(curr['open']), float(curr['close'])
|
curr_open, curr_close = float(curr['open']), float(curr['close'])
|
||||||
entry_open = float(entry_candle['open'])
|
entry_open = float(entry_candle['open']) # 入场价
|
||||||
|
|
||||||
# 当前为涨,前一笔涨 + 包裹 => 做多信号
|
trade_signal = None # 信号类型:long / short
|
||||||
if curr_close > curr_open and prev_close > prev_open and curr_open < prev_open and curr_close > prev_close:
|
|
||||||
|
# ======================== 做多条件 ========================
|
||||||
|
if (
|
||||||
|
curr_close > curr_open and prev_close > prev_open and # 连续两根阳线
|
||||||
|
curr_open < prev_open and curr_close > prev_close # 当前包住前一根
|
||||||
|
):
|
||||||
|
trade_signal = "long"
|
||||||
|
|
||||||
|
# ======================== 做空条件 ========================
|
||||||
|
elif (
|
||||||
|
curr_close < curr_open and prev_close < prev_open and # 连续两根阴线
|
||||||
|
curr_open > prev_open and curr_close < prev_close # 当前包住前一根
|
||||||
|
):
|
||||||
|
trade_signal = "short"
|
||||||
|
|
||||||
|
# ======================== 执行交易 ========================
|
||||||
|
if trade_signal:
|
||||||
signals += 1
|
signals += 1
|
||||||
take_profit = entry_open * 1.10 # 止盈 10%
|
|
||||||
stop_loss = entry_open * 0.95 # 止损 5%
|
|
||||||
exit_price = None
|
|
||||||
exit_time = None
|
|
||||||
|
|
||||||
# ✅ 往后遍历直到触发止盈 / 止损
|
# 设定止盈止损
|
||||||
|
if trade_signal == "long":
|
||||||
|
take_profit = entry_open * 1.002
|
||||||
|
stop_loss = entry_open * 0.998
|
||||||
|
else:
|
||||||
|
take_profit = entry_open * 0.9985
|
||||||
|
stop_loss = entry_open * 1.001
|
||||||
|
|
||||||
|
exit_price = None # 出场价格
|
||||||
|
exit_time = None # 出场时间
|
||||||
|
|
||||||
|
# 遍历后续K线,寻找止盈/止损
|
||||||
for future in sorted_data[idx + 2:]:
|
for future in sorted_data[idx + 2:]:
|
||||||
high, low, close = float(future['high']), float(future['low']), float(future['close'])
|
high, low, close = float(future['high']), float(future['low']), float(future['close'])
|
||||||
# 先判断是否触发止盈
|
|
||||||
if high >= take_profit:
|
if trade_signal == "long":
|
||||||
exit_price = take_profit
|
if high >= take_profit: # 触发止盈
|
||||||
exit_time = future["id"]
|
exit_price = take_profit
|
||||||
break
|
exit_time = future["id"]
|
||||||
# 判断是否触发止损
|
break
|
||||||
if low <= stop_loss:
|
if low <= stop_loss: # 触发止损
|
||||||
exit_price = stop_loss
|
exit_price = stop_loss
|
||||||
exit_time = future["id"]
|
exit_time = future["id"]
|
||||||
break
|
break
|
||||||
|
else: # short
|
||||||
|
if low <= take_profit: # 触发止盈
|
||||||
|
exit_price = take_profit
|
||||||
|
exit_time = future["id"]
|
||||||
|
break
|
||||||
|
if high >= stop_loss: # 触发止损
|
||||||
|
exit_price = stop_loss
|
||||||
|
exit_time = future["id"]
|
||||||
|
break
|
||||||
|
|
||||||
# 如果没触发止盈止损,用最后一根收盘价离场
|
# 如果没触发止盈止损,用最后一根收盘价离场
|
||||||
if exit_price is None:
|
if exit_price is None:
|
||||||
exit_price = float(sorted_data[-1]['close'])
|
exit_price = float(sorted_data[-1]['close'])
|
||||||
exit_time = sorted_data[-1]["id"]
|
exit_time = sorted_data[-1]["id"]
|
||||||
|
|
||||||
diff = exit_price - entry_open
|
# ======================== 盈亏计算 ========================
|
||||||
lig_price += diff
|
if trade_signal == "long":
|
||||||
all_trades.append((f"{day}号", entry_candle["id"], "做多", entry_open, exit_price, diff, exit_time))
|
diff = exit_price - entry_open # 多单盈亏
|
||||||
|
lig_price += diff
|
||||||
|
else:
|
||||||
|
diff = entry_open - exit_price # 空单盈亏
|
||||||
|
low_price += diff
|
||||||
|
|
||||||
|
# 保存交易详情
|
||||||
|
all_trades.append(
|
||||||
|
(f"{day}号", entry_candle["id"], "做多" if trade_signal == "long" else "做空",
|
||||||
|
entry_open, exit_price, diff, exit_time)
|
||||||
|
)
|
||||||
|
|
||||||
|
# 统计胜率
|
||||||
if diff > 0:
|
if diff > 0:
|
||||||
wins += 1
|
wins += 1
|
||||||
|
|
||||||
@@ -92,13 +159,17 @@ if __name__ == '__main__':
|
|||||||
zh_project = 0
|
zh_project = 0
|
||||||
all_trades = []
|
all_trades = []
|
||||||
|
|
||||||
|
# 回测 9月27日的数据
|
||||||
for i in range(27, 28):
|
for i in range(27, 28):
|
||||||
sorted_data = fetch_kline(i)
|
sorted_data = fetch_kline(i)
|
||||||
signals, wins, lig_price, low_price, trades = backtest_kline(sorted_data, i)
|
signals, wins, lig_price, low_price, trades = backtest_kline(sorted_data, i)
|
||||||
|
|
||||||
|
# 输出当天结果
|
||||||
if signals > 0:
|
if signals > 0:
|
||||||
logger.info(
|
logger.info(
|
||||||
f"日期:{i}号,信号数={signals}, 胜率={wins / signals * 100:.2f}%,上涨方向:{lig_price:.2f},下跌方向:{low_price:.2f},综合价格:{(lig_price + low_price):.2f}"
|
f"日期:{i}号,信号数={signals}, 胜率={wins / signals * 100:.2f}%,"
|
||||||
|
f"上涨方向:{lig_price:.2f},下跌方向:{low_price:.2f},"
|
||||||
|
f"综合价格:{(lig_price + low_price):.2f}"
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
logger.info(f"日期:{i}号,没有信号")
|
logger.info(f"日期:{i}号,没有信号")
|
||||||
@@ -106,22 +177,27 @@ if __name__ == '__main__':
|
|||||||
zh_project += (lig_price + low_price)
|
zh_project += (lig_price + low_price)
|
||||||
all_trades.extend(trades)
|
all_trades.extend(trades)
|
||||||
|
|
||||||
|
# ======================== 汇总输出 ========================
|
||||||
logger.success(f"综合价格:{zh_project:.2f}")
|
logger.success(f"综合价格:{zh_project:.2f}")
|
||||||
|
|
||||||
# 输出每笔交易
|
|
||||||
logger.info("===== 每笔交易详情 =====")
|
logger.info("===== 每笔交易详情 =====")
|
||||||
n = n1 = 0
|
n = n1 = 0 # n: 总盈利, n1: 总手续费
|
||||||
for trade in all_trades:
|
for trade in all_trades:
|
||||||
date, time_str, direction, entry, exit, diff, end_time = trade
|
date, time_str, direction, entry, exit, diff, end_time = trade
|
||||||
fee_open = 5
|
|
||||||
fee_close = 10000 / entry * exit * 0.0005
|
fee_open = 5 # 固定开仓手续费
|
||||||
|
fee_close = 10000 / entry * exit * 0.0005 # 平仓手续费
|
||||||
|
|
||||||
logger.info(
|
logger.info(
|
||||||
f"{date} {time_str} {direction} 入场={entry:.2f} 出场={exit:.2f} 出场时间:{end_time} 差价={diff:.2f} 盈利:{diff / entry * 10000:.2f} "
|
f"{date} {time_str} {direction} 入场={entry:.2f} 出场={exit:.2f} 出场时间:{end_time} "
|
||||||
|
f"差价={diff:.2f} 盈利:{diff / entry * 10000:.2f} "
|
||||||
f"开仓手续费:{fee_open:.2f} 平仓手续费:{fee_close:.2f}"
|
f"开仓手续费:{fee_open:.2f} 平仓手续费:{fee_close:.2f}"
|
||||||
)
|
)
|
||||||
|
|
||||||
n1 += fee_open + fee_close
|
n1 += fee_open + fee_close
|
||||||
n += (diff / entry) * 10000
|
n += (diff / entry) * 10000
|
||||||
|
|
||||||
|
# 输出汇总结果
|
||||||
print(f'一共笔数:{len(all_trades)}')
|
print(f'一共笔数:{len(all_trades)}')
|
||||||
print(f"一共盈利:{n:.2f}")
|
print(f"一共盈利:{n:.2f}")
|
||||||
print(f'一共手续费:{n1:.2f}')
|
print(f'一共手续费:{n1:.2f}')
|
||||||
|
|||||||
Reference in New Issue
Block a user