增加交易策略、交易指标、量化库代码等文件夹

This commit is contained in:
Win_home
2025-04-27 15:54:09 +08:00
parent ca3b209096
commit f57150dae8
589 changed files with 854346 additions and 1757 deletions

View File

@@ -0,0 +1,297 @@
import backtrader as bt
from datetime import datetime
from datetime import time as s_time
from backtrader.feeds import GenericCSVData
import numpy as np
# import pandas as pd
import itertools
import multiprocessing
import talib as tb
class GenericCSV_SIG(GenericCSVData):
lines = ("sig", "delta")
params = (("sig", 6), ("delta", 8))
class MyStrategy_固定止损_跟踪止盈(bt.Strategy):
params = (
("trailing_stop_percent", 0.02),
("fixed_stop_loss_percent", 0.01),
("duiji", 1),
("cout_delta", 1),
("delta", 1),
)
def __init__(self):
self.Lots = 1
self.signal = self.datas[0].sig
self.delta = self.datas[0].delta
self.pos = 0
self.high = self.datas[0].high
self.low = self.datas[0].low
self.closes = self.datas[0].close
self.open = self.datas[0].open
self.trailing_stop_percent = self.params.trailing_stop_percent
self.short_trailing_stop_price = 0
self.long_trailing_stop_price = 0
self.fixed_stop_loss_percent = self.params.fixed_stop_loss_percent
self.sl_long_price = 0
self.sl_shor_price = 0
self.out_long = 0
self.out_short = 0
self.rinei_ma = []
self.renei_open_ma = []
self.renei_high_ma = []
self.renei_low_ma = []
self.rinei_mean = 0
self.reniei_bop = []
self.datetime_list = []
self.high_list = []
self.low_list = []
self.close_list = []
self.opens_list = []
self.deltas_list = []
self.delta_cumsum = []
self.barN = 0
def log(self, txt, dt=None):
dt = dt or self.datas[0].datetime.date(0)
print("%s, %s" % (dt.isoformat(), txt))
def next(self):
self.barN += 1
# position = self.getposition(self.datas[0]).size
dt = bt.num2date(self.data.datetime[0])
def 每日重置数据():
current_time = dt.time()
clearing_time1_start = s_time(14, 55)
clearing_time1_end = s_time(15, 0)
clearing_time2_start = s_time(2, 25)
clearing_time2_end = s_time(2, 30)
clearing_executed = False
if clearing_time1_start <= current_time <= clearing_time1_end and not clearing_executed:
clearing_executed = True
self.rinei_ma = []
self.renei_open_ma = []
self.renei_high_ma = []
self.renei_low_ma = []
self.delta_cumsum = []
self.deltas_list = []
elif clearing_time2_start <= current_time <= clearing_time2_end and not clearing_executed:
clearing_executed = True
self.rinei_ma = []
self.renei_open_ma = []
self.renei_high_ma = []
self.renei_low_ma = []
self.delta_cumsum = []
self.deltas_list = []
else:
self.rinei_ma.append(self.closes[0])
self.renei_open_ma.append(self.open[0])
self.renei_high_ma.append(self.high[0])
self.renei_low_ma.append(self.low[0])
self.rinei_mean = np.mean(self.rinei_ma)
self.reniei_bop = tb.BOP(
np.array(self.renei_open_ma),
np.array(self.renei_high_ma),
np.array(self.renei_low_ma),
np.array(self.rinei_ma),
)
clearing_executed = False
return clearing_executed
run_kg = 每日重置数据()
if self.data.volume[0] <= 0:
return
if self.long_trailing_stop_price > 0 and self.pos > 0:
self.long_trailing_stop_price = max(self.low[0], self.long_trailing_stop_price)
if self.short_trailing_stop_price > 0 and self.pos < 0:
self.short_trailing_stop_price = min(self.high[0], self.short_trailing_stop_price)
self.out_long = self.long_trailing_stop_price * (1 - self.trailing_stop_percent)
self.out_short = self.short_trailing_stop_price * (1 + self.trailing_stop_percent)
if (
self.out_long > 0
and self.low[0] < self.out_long
and self.pos > 0
and self.sl_long_price > 0
and self.low[0] > self.sl_long_price
):
self.close(data=self.data, price=self.data.close[0], size=self.Lots, exectype=bt.Order.Market)
self.long_trailing_stop_price = 0
self.sl_long_price = 0
self.out_long = 0
self.pos = 0
if (
self.out_short > 0
and self.high[0] > self.out_short
and self.pos < 0
and self.sl_shor_price > 0
and self.high[0] < self.sl_shor_price
):
self.close(data=self.data, price=self.data.close[0], size=self.Lots, exectype=bt.Order.Market)
self.short_trailing_stop_price = 0
self.sl_shor_price = 0
self.out_short = 0
self.pos = 0
self.fixed_stop_loss_L = self.sl_long_price * (1 - self.fixed_stop_loss_percent)
if (
self.sl_long_price > 0
and self.fixed_stop_loss_L > 0
and self.pos > 0
and self.closes[0] < self.fixed_stop_loss_L
):
self.close(data=self.data, price=self.data.close[0], size=self.Lots, exectype=bt.Order.Market)
self.long_trailing_stop_price = 0
self.sl_long_price = 0
self.out_long = 0
self.pos = 0
self.fixed_stop_loss_S = self.sl_shor_price * (1 + self.fixed_stop_loss_percent)
if (
self.sl_shor_price > 0
and self.fixed_stop_loss_S > 0
and self.pos < 0
and self.closes[0] > self.fixed_stop_loss_S
):
self.close(data=self.data, price=self.data.close[0], size=self.Lots, exectype=bt.Order.Market)
self.short_trailing_stop_price = 0
self.sl_shor_price = 0
self.out_short = 0
self.pos = 0
self.datetime_list.append(dt)
self.high_list.append(self.data.high[0])
self.low_list.append(self.data.low[0])
self.close_list.append(self.data.close[0])
self.opens_list.append(self.data.open[0])
self.deltas_list.append(self.data.delta[0])
self.delta_cumsum.append(sum(self.deltas_list))
if run_kg is False:
t3 = tb.T3(np.array(self.deltas_list))
t3_cum = tb.T3(np.array(self.delta_cumsum))
# 开多组合 = self.rinei_mean > 0 and self.closes[0] > self.rinei_mean and self.signal[0] > self.params.duiji and self.data.delta[0] > self.params.delta and self.delta_cumsum[-1] > self.params.cout_delta
# 开空组合 = self.rinei_mean > 0 and self.closes[0] < self.rinei_mean and self.signal[0] < -self.params.duiji and self.data.delta[0] < -self.params.delta and self.delta_cumsum[-1] < -self.params.cout_delta
开多组合 = (
self.reniei_bop[-1] > 0
and self.signal[0] > self.params.duiji
and self.data.delta[0] > t3[-1] # self.params.delta
and self.delta_cumsum[-1] > t3_cum[-1] # self.params.cout_delta
)
开空组合 = (
self.reniei_bop[-1] < 0
and self.signal[0] < -self.params.duiji
and self.data.delta[0] < t3[-1] # -self.params.delta
and self.delta_cumsum[-1] < t3_cum[-1] # -self.params.cout_delta
)
平多条件 = self.pos < 0 and self.signal[0] > self.params.duiji
平空条件 = self.pos > 0 and self.signal[0] < -self.params.duiji
if self.pos != 1:
if 平多条件:
self.close(data=self.data, price=self.data.close[0], exectype=bt.Order.Market)
self.short_trailing_stop_price = 0
self.sl_shor_price = 0
self.out_short = 0
self.pos = 0
if 开多组合:
self.buy(data=self.data, price=self.data.close[0], size=1, exectype=bt.Order.Market)
self.pos = 1
self.long_trailing_stop_price = self.low[0]
self.sl_long_price = self.data.open[0]
if self.pos != -1:
if 平空条件:
self.close(data=self.data, price=self.data.close[0], exectype=bt.Order.Market)
self.long_trailing_stop_price = 0
self.sl_long_price = 0
self.out_long = 0
self.pos = 0
if 开空组合:
self.sell(data=self.data, price=self.data.close[0], size=1, exectype=bt.Order.Market)
self.pos = -1
self.short_trailing_stop_price = self.high[0]
self.sl_shor_price = self.data.open[0]
def evaluate_strategy(trailing_stop_percent, fixed_stop_loss_percent, duiji, cout_delta, delta, csv_file):
cerebro = bt.Cerebro()
cerebro.addstrategy(
MyStrategy_固定止损_跟踪止盈,
trailing_stop_percent=trailing_stop_percent,
fixed_stop_loss_percent=fixed_stop_loss_percent,
duiji=duiji,
cout_delta=cout_delta,
delta=delta,
)
data = GenericCSV_SIG(
dataname=csv_file,
fromdate=datetime(2020, 1, 1),
todate=datetime(2023, 12, 29),
timeframe=bt.TimeFrame.Minutes,
nullvalue=0.0,
dtformat="%Y-%m-%d %H:%M:%S",
datetime=0,
high=3,
low=4,
open=2,
close=1,
volume=5,
openinterest=None,
sig=6,
delta=8,
)
cerebro.adddata(data)
cerebro.broker.setcash(300000.0)
cerebro.broker.setcommission(commission=14, margin=150000.0, mult=300)
cerebro.run()
return cerebro.broker.getvalue(), (trailing_stop_percent, fixed_stop_loss_percent, duiji, cout_delta, delta)
def run_backtest(params):
trailing_stop_percent, fixed_stop_loss_percent, duiji, cout_delta, delta, csv_file = params
return evaluate_strategy(trailing_stop_percent, fixed_stop_loss_percent, duiji, cout_delta, delta, csv_file)
if __name__ == "__main__":
csv_file = r"D:\BaiduNetdiskDownload\主力连续\tick生成的OF数据(5M)\data_rs_merged\中金所\IM888\IM888_rs_2023_5T_back_ofdata_dj_new.csv"
trailing_stop_percents = np.arange(0.005, 0.025, 0.005)
fixed_stop_loss_percents = np.arange(0.01, 0.050, 0.01)
duiji = np.arange(1, 4, 1)
cout_delta = np.arange(100000, 200000, 100000) # (500, 3500, 500)
delta = np.arange(100000, 200000, 100000) # (500, 3500, 500)
combinations = list(itertools.product(trailing_stop_percents, fixed_stop_loss_percents, duiji, cout_delta, delta))
combinations = [(tsp, fslp, d, cd, dl, csv_file) for tsp, fslp, d, cd, dl in combinations]
with multiprocessing.Pool(processes=multiprocessing.cpu_count()) as pool:
results = pool.map(run_backtest, combinations)
best_value = 0
best_parameters = None
for value, params in results:
if value > best_value:
best_value = value
best_parameters = params
print(f"combo: {params}, value: {value}, best_value: {best_value}, best_parameters: {best_parameters}")
print(f"最佳参数组合: 跟踪止损百分比 {best_parameters[0]}%, 固定止损百分比 {best_parameters[1]}%")
print(f"最大市值: {best_value}")
# trailing_stop_percent, fixed_stop_loss_percent, duiji, cout_delta, delta
# IM
# 5M(0.01, 0.02, 2, 700000, 500000)
# 1M(0.005, 0.02, 3, 100000, 200000)
# IF
# 5M(0.005, 0.02, 1, 100000, 400000)

View File

@@ -0,0 +1,286 @@
import backtrader as bt
from datetime import datetime
from datetime import time as s_time
from backtrader.feeds import GenericCSVData
import numpy as np
import pandas as pd
import itertools
import multiprocessing
import talib as tb
class GenericCSV_SIG(GenericCSVData):
lines = ("sig", "delta")
params = (("sig", 6), ("delta", 8))
class MyStrategy_固定止损_跟踪止盈(bt.Strategy):
params = (
("trailing_stop_percent", 0.02),
("fixed_stop_loss_percent", 0.01),
("duiji", 1),
("cout_delta", 1),
("delta", 1),
)
def __init__(self):
self.Lots = 1
self.signal = self.datas[0].sig
self.delta = self.datas[0].delta
self.pos = 0
self.high = self.datas[0].high
self.low = self.datas[0].low
self.closes = self.datas[0].close
self.open = self.datas[0].open
self.trailing_stop_percent = self.params.trailing_stop_percent
self.short_trailing_stop_price = 0
self.long_trailing_stop_price = 0
self.fixed_stop_loss_percent = self.params.fixed_stop_loss_percent
self.sl_long_price = 0
self.sl_shor_price = 0
self.out_long = 0
self.out_short = 0
self.rinei_ma = []
self.renei_high_ma = []
self.renei_low_ma = []
self.rinei_mean = 0
self.reniei_sar = []
self.datetime_list = []
self.high_list = []
self.low_list = []
self.close_list = []
self.opens_list = []
self.deltas_list = []
self.delta_cumsum = []
self.barN = 0
def log(self, txt, dt=None):
dt = dt or self.datas[0].datetime.date(0)
print("%s, %s" % (dt.isoformat(), txt))
def next(self):
self.barN += 1
position = self.getposition(self.datas[0]).size
dt = bt.num2date(self.data.datetime[0])
def 每日重置数据():
current_time = dt.time()
clearing_time1_start = s_time(14, 55)
clearing_time1_end = s_time(15, 0)
clearing_time2_start = s_time(2, 25)
clearing_time2_end = s_time(2, 30)
clearing_executed = False
if clearing_time1_start <= current_time <= clearing_time1_end and not clearing_executed:
clearing_executed = True
self.rinei_ma = []
self.renei_high_ma = []
self.renei_low_ma = []
self.delta_cumsum = []
self.deltas_list = []
elif clearing_time2_start <= current_time <= clearing_time2_end and not clearing_executed:
clearing_executed = True
self.rinei_ma = []
self.renei_high_ma = []
self.renei_low_ma = []
self.delta_cumsum = []
self.deltas_list = []
else:
self.rinei_ma.append(self.closes[0])
self.renei_high_ma.append(self.high[0])
self.renei_low_ma.append(self.low[0])
self.rinei_mean = np.mean(self.rinei_ma)
self.reniei_sar = tb.SAR(np.array(self.renei_high_ma), np.array(self.renei_low_ma), 0.02, 0.2)
clearing_executed = False
return clearing_executed
run_kg = 每日重置数据()
if self.data.volume[0] <= 0:
return
if self.long_trailing_stop_price > 0 and self.pos > 0:
self.long_trailing_stop_price = max(self.low[0], self.long_trailing_stop_price)
if self.short_trailing_stop_price > 0 and self.pos < 0:
self.short_trailing_stop_price = min(self.high[0], self.short_trailing_stop_price)
self.out_long = self.long_trailing_stop_price * (1 - self.trailing_stop_percent)
self.out_short = self.short_trailing_stop_price * (1 + self.trailing_stop_percent)
if (
self.out_long > 0
and self.low[0] < self.out_long
and self.pos > 0
and self.sl_long_price > 0
and self.low[0] > self.sl_long_price
):
self.close(data=self.data, price=self.data.close[0], size=self.Lots, exectype=bt.Order.Market)
self.long_trailing_stop_price = 0
self.sl_long_price = 0
self.out_long = 0
self.pos = 0
if (
self.out_short > 0
and self.high[0] > self.out_short
and self.pos < 0
and self.sl_shor_price > 0
and self.high[0] < self.sl_shor_price
):
self.close(data=self.data, price=self.data.close[0], size=self.Lots, exectype=bt.Order.Market)
self.short_trailing_stop_price = 0
self.sl_shor_price = 0
self.out_short = 0
self.pos = 0
self.fixed_stop_loss_L = self.sl_long_price * (1 - self.fixed_stop_loss_percent)
if (
self.sl_long_price > 0
and self.fixed_stop_loss_L > 0
and self.pos > 0
and self.closes[0] < self.fixed_stop_loss_L
):
self.close(data=self.data, price=self.data.close[0], size=self.Lots, exectype=bt.Order.Market)
self.long_trailing_stop_price = 0
self.sl_long_price = 0
self.out_long = 0
self.pos = 0
self.fixed_stop_loss_S = self.sl_shor_price * (1 + self.fixed_stop_loss_percent)
if (
self.sl_shor_price > 0
and self.fixed_stop_loss_S > 0
and self.pos < 0
and self.closes[0] > self.fixed_stop_loss_S
):
self.close(data=self.data, price=self.data.close[0], size=self.Lots, exectype=bt.Order.Market)
self.short_trailing_stop_price = 0
self.sl_shor_price = 0
self.out_short = 0
self.pos = 0
self.datetime_list.append(dt)
self.high_list.append(self.data.high[0])
self.low_list.append(self.data.low[0])
self.close_list.append(self.data.close[0])
self.opens_list.append(self.data.open[0])
self.deltas_list.append(self.data.delta[0])
self.delta_cumsum.append(sum(self.deltas_list))
if run_kg == False:
# 开多组合 = self.rinei_mean > 0 and self.closes[0] > self.rinei_mean and self.signal[0] > self.params.duiji and self.data.delta[0] > self.params.delta and self.delta_cumsum[-1] > self.params.cout_delta
# 开空组合 = self.rinei_mean > 0 and self.closes[0] < self.rinei_mean and self.signal[0] < -self.params.duiji and self.data.delta[0] < -self.params.delta and self.delta_cumsum[-1] < -self.params.cout_delta
开多组合 = (
self.reniei_sar[-1] > self.closes[0]
and self.signal[0] > self.params.duiji
and self.data.delta[0] > self.params.delta
and self.delta_cumsum[-1] > self.params.cout_delta
)
开空组合 = (
self.reniei_sar[-1] < self.closes[0]
and self.signal[0] < -self.params.duiji
and self.data.delta[0] < -self.params.delta
and self.delta_cumsum[-1] < -self.params.cout_delta
)
平多条件 = self.pos < 0 and self.signal[0] > self.params.duiji
平空条件 = self.pos > 0 and self.signal[0] < -self.params.duiji
if self.pos != 1:
if 平多条件:
self.close(data=self.data, price=self.data.close[0], exectype=bt.Order.Market)
self.short_trailing_stop_price = 0
self.sl_shor_price = 0
self.out_short = 0
self.pos = 0
if 开多组合:
self.buy(data=self.data, price=self.data.close[0], size=1, exectype=bt.Order.Market)
self.pos = 1
self.long_trailing_stop_price = self.low[0]
self.sl_long_price = self.data.open[0]
if self.pos != -1:
if 平空条件:
self.close(data=self.data, price=self.data.close[0], exectype=bt.Order.Market)
self.long_trailing_stop_price = 0
self.sl_long_price = 0
self.out_long = 0
self.pos = 0
if 开空组合:
self.sell(data=self.data, price=self.data.close[0], size=1, exectype=bt.Order.Market)
self.pos = -1
self.short_trailing_stop_price = self.high[0]
self.sl_shor_price = self.data.open[0]
def evaluate_strategy(trailing_stop_percent, fixed_stop_loss_percent, duiji, cout_delta, delta, csv_file):
cerebro = bt.Cerebro()
cerebro.addstrategy(
MyStrategy_固定止损_跟踪止盈,
trailing_stop_percent=trailing_stop_percent,
fixed_stop_loss_percent=fixed_stop_loss_percent,
duiji=duiji,
cout_delta=cout_delta,
delta=delta,
)
data = GenericCSV_SIG(
dataname=csv_file,
fromdate=datetime(2020, 1, 1),
todate=datetime(2023, 12, 29),
timeframe=bt.TimeFrame.Minutes,
nullvalue=0.0,
dtformat="%Y-%m-%d %H:%M:%S",
datetime=0,
high=3,
low=4,
open=2,
close=1,
volume=5,
openinterest=None,
sig=6,
delta=8,
)
cerebro.adddata(data)
cerebro.broker.setcash(300000.0)
cerebro.broker.setcommission(commission=14, margin=150000.0, mult=300)
cerebro.run()
return cerebro.broker.getvalue(), (trailing_stop_percent, fixed_stop_loss_percent, duiji, cout_delta, delta)
def run_backtest(params):
trailing_stop_percent, fixed_stop_loss_percent, duiji, cout_delta, delta, csv_file = params
return evaluate_strategy(trailing_stop_percent, fixed_stop_loss_percent, duiji, cout_delta, delta, csv_file)
if __name__ == "__main__":
csv_file = r"D:\BaiduNetdiskDownload\主力连续\tick生成的OF数据(5M)\data_rs_merged\中金所\IM888\IM888_rs_2023_5T_back_ofdata_dj.csv"
trailing_stop_percents = np.arange(0.005, 0.025, 0.005)
fixed_stop_loss_percents = np.arange(0.01, 0.050, 0.01)
duiji = np.arange(1, 4, 1)
cout_delta = np.arange(100000, 800000, 100000) # (500, 3500, 500)
delta = np.arange(100000, 800000, 100000) # (500, 3500, 500)
combinations = list(itertools.product(trailing_stop_percents, fixed_stop_loss_percents, duiji, cout_delta, delta))
combinations = [(tsp, fslp, d, cd, dl, csv_file) for tsp, fslp, d, cd, dl in combinations]
with multiprocessing.Pool(processes=multiprocessing.cpu_count()) as pool:
results = pool.map(run_backtest, combinations)
best_value = 0
best_parameters = None
for value, params in results:
if value > best_value:
best_value = value
best_parameters = params
print(f"combo: {params}, value: {value}, best_value: {best_value}, best_parameters: {best_parameters}")
print(f"最佳参数组合: 跟踪止损百分比 {best_parameters[0]}%, 固定止损百分比 {best_parameters[1]}%")
print(f"最大市值: {best_value}")
# trailing_stop_percent, fixed_stop_loss_percent, duiji, cout_delta, delta
# IM
# 5M(0.01, 0.02, 2, 700000, 500000)
# 1M(0.005, 0.02, 3, 100000, 200000)
# IF
# 5M(0.005, 0.02, 1, 100000, 400000)

View File

@@ -0,0 +1,382 @@
import backtrader as bt
from datetime import datetime
from datetime import time as s_time
from backtrader.feeds import GenericCSVData
import numpy as np
# import pandas as pd
import itertools
import multiprocessing
import talib as tb
class GenericCSV_SIG(GenericCSVData):
lines = ("sig", "delta")
params = (("sig", 6), ("delta", 8))
class MyStrategy_固定止损_跟踪止盈(bt.Strategy):
params = (
("trailing_stop_percent", 0.02),
("fixed_stop_loss_percent", 0.01),
("duiji", 1),
("cout_delta", 1),
("delta", 1),
)
def __init__(self):
self.Lots = 1
self.signal = self.datas[0].sig
self.delta = self.datas[0].delta
self.pos = 0
self.high = self.datas[0].high
self.low = self.datas[0].low
self.closes = self.datas[0].close
self.open = self.datas[0].open
self.trailing_stop_percent = self.params.trailing_stop_percent
self.short_trailing_stop_price = 0
self.long_trailing_stop_price = 0
self.fixed_stop_loss_percent = self.params.fixed_stop_loss_percent
self.sl_long_price = 0
self.sl_shor_price = 0
self.out_long = 0
self.out_short = 0
self.rinei_ma = []
self.renei_open_ma = []
self.renei_high_ma = []
self.renei_low_ma = []
self.rinei_mean = 0
self.reniei_indicator = []
self.datetime_list = []
self.high_list = []
self.low_list = []
self.close_list = []
self.opens_list = []
self.deltas_list = []
self.delta_cumsum = []
self.barN = 0
def log(self, txt, dt=None):
dt = dt or self.datas[0].datetime.date(0)
print("%s, %s" % (dt.isoformat(), txt))
def next(self):
self.barN += 1
# position = self.getposition(self.datas[0]).size
dt = bt.num2date(self.data.datetime[0])
def 每日重置数据():
current_time = dt.time()
clearing_time1_start = s_time(14, 55)
clearing_time1_end = s_time(15, 0)
clearing_time2_start = s_time(2, 25)
clearing_time2_end = s_time(2, 30)
clearing_executed = False
if (
clearing_time1_start <= current_time <= clearing_time1_end
and not clearing_executed
):
clearing_executed = True
self.rinei_ma = []
self.renei_open_ma = []
self.renei_high_ma = []
self.renei_low_ma = []
self.delta_cumsum = []
self.deltas_list = []
elif (
clearing_time2_start <= current_time <= clearing_time2_end
and not clearing_executed
):
clearing_executed = True
self.rinei_ma = []
self.renei_open_ma = []
self.renei_high_ma = []
self.renei_low_ma = []
self.delta_cumsum = []
self.deltas_list = []
else:
self.rinei_ma.append(self.closes[0])
self.renei_open_ma.append(self.open[0])
self.renei_high_ma.append(self.high[0])
self.renei_low_ma.append(self.low[0])
self.rinei_mean = np.mean(self.rinei_ma)
self.reniei_indicator = tb.AROONOSC(
np.array(self.renei_high_ma),
np.array(self.renei_low_ma),
self.params.delta,
)
clearing_executed = False
return clearing_executed
run_kg = 每日重置数据()
if self.data.volume[0] <= 0:
return
if self.long_trailing_stop_price > 0 and self.pos > 0:
self.long_trailing_stop_price = max(
self.low[0], self.long_trailing_stop_price
)
if self.short_trailing_stop_price > 0 and self.pos < 0:
self.short_trailing_stop_price = min(
self.high[0], self.short_trailing_stop_price
)
self.out_long = self.long_trailing_stop_price * (1 - self.trailing_stop_percent)
self.out_short = self.short_trailing_stop_price * (
1 + self.trailing_stop_percent
)
if (
self.out_long > 0
and self.low[0] < self.out_long
and self.pos > 0
and self.sl_long_price > 0
and self.low[0] > self.sl_long_price
):
self.close(
data=self.data,
price=self.data.close[0],
size=self.Lots,
exectype=bt.Order.Market,
)
self.long_trailing_stop_price = 0
self.sl_long_price = 0
self.out_long = 0
self.pos = 0
if (
self.out_short > 0
and self.high[0] > self.out_short
and self.pos < 0
and self.sl_shor_price > 0
and self.high[0] < self.sl_shor_price
):
self.close(
data=self.data,
price=self.data.close[0],
size=self.Lots,
exectype=bt.Order.Market,
)
self.short_trailing_stop_price = 0
self.sl_shor_price = 0
self.out_short = 0
self.pos = 0
self.fixed_stop_loss_L = self.sl_long_price * (1 - self.fixed_stop_loss_percent)
if (
self.sl_long_price > 0
and self.fixed_stop_loss_L > 0
and self.pos > 0
and self.closes[0] < self.fixed_stop_loss_L
):
self.close(
data=self.data,
price=self.data.close[0],
size=self.Lots,
exectype=bt.Order.Market,
)
self.long_trailing_stop_price = 0
self.sl_long_price = 0
self.out_long = 0
self.pos = 0
self.fixed_stop_loss_S = self.sl_shor_price * (1 + self.fixed_stop_loss_percent)
if (
self.sl_shor_price > 0
and self.fixed_stop_loss_S > 0
and self.pos < 0
and self.closes[0] > self.fixed_stop_loss_S
):
self.close(
data=self.data,
price=self.data.close[0],
size=self.Lots,
exectype=bt.Order.Market,
)
self.short_trailing_stop_price = 0
self.sl_shor_price = 0
self.out_short = 0
self.pos = 0
self.datetime_list.append(dt)
self.high_list.append(self.data.high[0])
self.low_list.append(self.data.low[0])
self.close_list.append(self.data.close[0])
self.opens_list.append(self.data.open[0])
self.deltas_list.append(self.data.delta[0])
self.delta_cumsum.append(sum(self.deltas_list))
if run_kg is False:
# t3 = tb.T3(np.array(self.deltas_list))
# t3_cum = tb.T3(np.array(self.delta_cumsum))
# 开多组合 = self.rinei_mean > 0 and self.closes[0] > self.rinei_mean and self.signal[0] > self.params.duiji and self.data.delta[0] > self.params.delta and self.delta_cumsum[-1] > self.params.cout_delta
# 开空组合 = self.rinei_mean > 0 and self.closes[0] < self.rinei_mean and self.signal[0] < -self.params.duiji and self.data.delta[0] < -self.params.delta and self.delta_cumsum[-1] < -self.params.cout_delta
开多组合 = (
self.reniei_indicator[-1] > 0
and self.signal[0] > self.params.duiji
and self.data.delta[0]
> max(self.deltas_list[-self.params.cout_delta : -1])
and self.delta_cumsum[-1]
> max(self.delta_cumsum[-self.params.cout_delta : -1])
)
开空组合 = (
self.reniei_indicator[-1] < 0
and self.signal[0] < -self.params.duiji
and self.data.delta[0]
< min(self.deltas_list[-self.params.cout_delta : -1])
and self.delta_cumsum[-1]
< min(self.delta_cumsum[-self.params.cout_delta : -1])
)
平多条件 = self.pos < 0 and self.signal[0] > self.params.duiji
平空条件 = self.pos > 0 and self.signal[0] < -self.params.duiji
if self.pos != 1:
if 平多条件:
self.close(
data=self.data,
price=self.data.close[0],
exectype=bt.Order.Market,
)
self.short_trailing_stop_price = 0
self.sl_shor_price = 0
self.out_short = 0
self.pos = 0
if 开多组合:
self.buy(
data=self.data,
price=self.data.close[0],
size=1,
exectype=bt.Order.Market,
)
self.pos = 1
self.long_trailing_stop_price = self.low[0]
self.sl_long_price = self.data.open[0]
if self.pos != -1:
if 平空条件:
self.close(
data=self.data,
price=self.data.close[0],
exectype=bt.Order.Market,
)
self.long_trailing_stop_price = 0
self.sl_long_price = 0
self.out_long = 0
self.pos = 0
if 开空组合:
self.sell(
data=self.data,
price=self.data.close[0],
size=1,
exectype=bt.Order.Market,
)
self.pos = -1
self.short_trailing_stop_price = self.high[0]
self.sl_shor_price = self.data.open[0]
def evaluate_strategy(
trailing_stop_percent, fixed_stop_loss_percent, duiji, cout_delta, delta, csv_file
):
cerebro = bt.Cerebro()
cerebro.addstrategy(
MyStrategy_固定止损_跟踪止盈,
trailing_stop_percent=trailing_stop_percent,
fixed_stop_loss_percent=fixed_stop_loss_percent,
duiji=duiji,
cout_delta=cout_delta,
delta=delta,
)
data = GenericCSV_SIG(
dataname=csv_file,
fromdate=datetime(2020, 1, 1),
todate=datetime(2023, 12, 29),
timeframe=bt.TimeFrame.Minutes,
nullvalue=0.0,
dtformat="%Y-%m-%d %H:%M:%S",
datetime=0,
high=3,
low=4,
open=2,
close=1,
volume=5,
openinterest=None,
sig=6,
delta=8,
)
cerebro.adddata(data)
cerebro.broker.setcash(300000.0)
cerebro.broker.setcommission(commission=14, margin=150000.0, mult=300)
cerebro.run()
return cerebro.broker.getvalue(), (
trailing_stop_percent,
fixed_stop_loss_percent,
duiji,
cout_delta,
delta,
)
def run_backtest(params):
(
trailing_stop_percent,
fixed_stop_loss_percent,
duiji,
cout_delta,
delta,
csv_file,
) = params
return evaluate_strategy(
trailing_stop_percent,
fixed_stop_loss_percent,
duiji,
cout_delta,
delta,
csv_file,
)
if __name__ == "__main__":
csv_file = r"E:\of_data\主力连续\tick生成的OF数据(5M)\data_rs_merged\中金所\IM888\IM888_rs_2023_5T_back_ofdata_dj.csv"
trailing_stop_percents = np.arange(0.005, 0.025, 0.005)
fixed_stop_loss_percents = np.arange(0.01, 0.050, 0.01)
duiji = np.arange(0, 4, 1)
cout_delta = np.arange(5, 20, 5) # (500, 3500, 500)
delta = np.arange(20, 120, 10) # (500, 3500, 500)
combinations = list(
itertools.product(
trailing_stop_percents, fixed_stop_loss_percents, duiji, cout_delta, delta
)
)
combinations = [
(tsp, fslp, d, cd, dl, csv_file) for tsp, fslp, d, cd, dl in combinations
]
with multiprocessing.Pool(processes=multiprocessing.cpu_count()) as pool:
results = pool.map(run_backtest, combinations)
best_value = 0
best_parameters = None
for value, params in results:
if value > best_value:
best_value = value
best_parameters = params
print(
f"combo: {params}, value: {value}, best_value: {best_value}, best_parameters: {best_parameters}"
)
print(
f"最佳参数组合: 跟踪止损百分比 {best_parameters[0]}%, 固定止损百分比 {best_parameters[1]}%"
)
print(f"最大市值: {best_value}")
# trailing_stop_percent, fixed_stop_loss_percent, duiji, cout_delta, delta
# IM
# 5M(0.01, 0.02, 2, 700000, 500000)
# 1M(0.005, 0.02, 3, 100000, 200000)
# IF
# 5M(0.005, 0.02, 1, 100000, 400000)

View File

@@ -0,0 +1,553 @@
"""
以下是代码的详细说明:
#公众号松鼠Quant
#主页www.quant789.com
#本策略仅作学习交流使用,实盘交易盈亏投资者个人负责!!!
#版权归松鼠Quant所有禁止转发、转卖源码违者必究。
1.
导入必要的模块和库:
backtrader 用于回测功能
datetime 用于处理日期和时间
GenericCSVData 用于从CSV文件加载数据
numpy 用于数值操作
time 用于时间相关操作
matplotlib.pyplot 用于绘图
2. 定义自定义手续费模板MyCommission
继承自bt.CommInfoBase
3.
定义自定义数据源类 GenericCSV_SIG
继承自 GenericCSVData并添加了两个额外的行'sig''delta'
定义了参数 'sig''delta'
4.
定义 MyStrategy_固定止损_跟踪止盈 类:
继承自 bt.Strategybacktrader的基础策略类
定义了两个参数trailing_stop_percent 和 fixed_stop_loss_percent
初始化策略并设置各种变量和指标
实现了 next 方法该方法在数据源的每个新的K线出现时被调用
根据当前K线数据更新跟踪止盈价格
实现了跟踪止盈出场和固定止损出场
根据信号处理多头和空头仓位
在策略执行过程中打印调试信息
5.
if __name__ == "__main__": 代码块:
使用 Cerebro 实例设置回测环境
使用 GenericCSV_SIG 数据源从CSV文件加载数据
将数据源和策略添加到 Cerebro 实例中
添加观察者和分析器以评估性能
设置初始资金和经纪人参数
运行回测并获取结果
打印回测报告,包括收益率、回撤、胜率和交易统计数据
6.使用前事项:
1、主程序中修改ofdata_dj文件地址、png_filepath地址
2、修改clearing_time2_start、clearing_time2_stop
3、修改交易参数:lots、跟踪止损百分、固定止损百分比、duiji、cout_delta、delta
4、修改资金参数:初始资金;回测参数:回测时间段、佣金、单边保证金、手续费;
"""
import backtrader as bt
from datetime import datetime
from datetime import time as s_time
from backtrader.feeds import GenericCSVData
import numpy as np
import pandas as pd
import os
import talib as tb # jerom注释 增加talib库
# import time
# import matplotlib.pyplot as plt
手续费汇总 = 0
class GenericCSV_SIG(GenericCSVData):
# 从基类继承,添加一个 'sig'delta
lines = ("sig", "delta")
# 添加参数为从基类继承的参数
params = (("sig", 6), ("delta", 8))
class MyStrategy_固定止损_跟踪止盈(bt.Strategy):
params = (
("trailing_stop_percent", 0.005), # 跟踪止盈百分比
("fixed_stop_loss_percent", 0.02), # 固定止损百分比
)
def __init__(self):
self.Lots = 1 # 下单手数
self.signal = self.datas[0].sig # 使用sig字段作为策略的信号字段
self.delta = self.datas[0].delta
# 获取数据序列别名列表
line_aliases = self.datas[0].getlinealiases()
self.pos = 0
print(line_aliases)
self.high = self.datas[0].high
self.low = self.datas[0].low
self.closes = self.datas[0].close
self.open = self.datas[0].open
self.trailing_stop_percent = self.params.trailing_stop_percent
self.short_trailing_stop_price = 0
self.long_trailing_stop_price = 0
self.fixed_stop_loss_percent = self.params.fixed_stop_loss_percent
self.sl_long_price = 0
self.sl_shor_price = 0
self.out_long = 0
# 240884432
self.out_short = 0
self.rinei_ma = []
self.renei_open_ma = []
self.renei_high_ma = []
self.renei_low_ma = []
self.rinei_mean = 0
self.reniei_bop = []
self.datetime_list = []
self.high_list = []
self.low_list = []
self.close_list = []
self.opens_list = []
self.deltas_list = []
self.delta_cumsum = []
self.barN = 0
self.df = pd.DataFrame(columns=["datetime", "high", "low", "close", "open", "delta", "delta_cumsum"])
self.trader_df = pd.DataFrame(columns=["open", "high", "low", "close", "volume", "openInterest", "delta"])
def log(self, txt, dt=None):
"""可选,构建策略打印日志的函数:可用于打印订单记录或交易记录等"""
dt = dt or self.datas[0].datetime.date(0)
print("%s, %s" % (dt.isoformat(), txt))
def notify_order(self, order):
# 未被处理的订单
if order.status in [order.Submitted, order.Accepted]:
return
# 已经处理的订单
if order.status in [order.Completed, order.Canceled, order.Margin]:
global 手续费汇总
if order.isbuy():
手续费汇总 += order.executed.comm
self.log(
"BUY EXECUTED, 订单编号:%.0f,成交价格: %.2f, 手续费滑点:%.2f, 成交量: %.2f, 品种: %s,手续费汇总:%.2f"
% (
order.ref, # 订单编号
order.executed.price, # 成交价
order.executed.comm, # 佣金
order.executed.size, # 成交量
order.data._name, # 品种名称
手续费汇总,
)
)
else: # Sell
手续费汇总 += order.executed.comm
self.log(
"SELL EXECUTED, 订单编号:%.0f,成交价格: %.2f, 手续费滑点:%.2f, 成交量: %.2f, 品种: %s,手续费汇总:%.2f"
% (
order.ref,
order.executed.price,
order.executed.comm,
order.executed.size,
order.data._name,
手续费汇总,
)
)
def next(self):
# 公众号松鼠Quant
# 主页www.quant789.com
# 本策略仅作学习交流使用,实盘交易盈亏投资者个人负责!!!
# 版权归松鼠Quant所有禁止转发、转卖源码违者必究。
# bar线计数初始化
self.barN += 1
position = self.getposition(self.datas[0]).size
# 时间轴
dt = bt.num2date(self.data.datetime[0])
# 更新跟踪止损价格
def 每日重置数据():
# 获取当前时间
current_time = dt.time()
# print(current_time)
# 设置清仓操作的时间范围114:55到15:00
clearing_time1_start = s_time(14, 55)
clearing_time1_end = s_time(15, 0)
# 设置清仓操作的时间范围200:55到01:00
clearing_time2_start = s_time(2, 25)
clearing_time2_end = s_time(2, 30)
# 创建一个标志变量
clearing_executed = False
if clearing_time1_start <= current_time <= clearing_time1_end and not clearing_executed:
clearing_executed = True # 设置标志变量为已执行
self.rinei_ma = []
self.renei_open_ma = []
self.renei_high_ma = []
self.renei_low_ma = []
self.delta_cumsum = []
self.deltas_list = []
elif clearing_time2_start <= current_time <= clearing_time2_end and not clearing_executed:
clearing_executed = True # 设置标志变量为已执行
self.rinei_ma = []
self.renei_open_ma = []
self.renei_high_ma = []
self.renei_low_ma = []
self.delta_cumsum = []
self.deltas_list = []
# 如果不在任何时间范围内,可以执行其他操作
else:
self.renei_open_ma.append(self.open[0])
self.rinei_ma.append(self.closes[0])
self.renei_high_ma.append(self.high[0])
self.renei_low_ma.append(self.low[0])
self.rinei_mean = np.mean(self.rinei_ma)
self.reniei_bop = tb.BOP(
np.array(self.renei_open_ma),
np.array(self.renei_high_ma),
np.array(self.renei_low_ma),
np.array(self.rinei_ma),
)
# self.delta_cumsum=[]
# self.deltas_list=[]
# print('rinei_ma',self.rinei_ma)
clearing_executed = False
pass
return clearing_executed
run_kg = 每日重置数据()
# 过滤成交量为0或小于0
if self.data.volume[0] <= 0:
return
# print(f'volume,{self.data.volume[0]}')
if self.long_trailing_stop_price > 0 and self.pos > 0:
# print('datetime+sig: ',dt,'旧多头出线',self.long_trailing_stop_price,'low',self.low[0])
self.long_trailing_stop_price = (
self.low[0] if self.long_trailing_stop_price < self.low[0] else self.long_trailing_stop_price
)
# print('datetime+sig: ',dt,'多头出线',self.long_trailing_stop_price)
if self.short_trailing_stop_price > 0 and self.pos < 0:
# print('datetime+sig: ',dt,'旧空头出线',self.short_trailing_stop_price,'high',self.high[0])
self.short_trailing_stop_price = (
self.high[0] if self.high[0] < self.short_trailing_stop_price else self.short_trailing_stop_price
)
# print('datetime+sig: ',dt,'空头出线',self.short_trailing_stop_price)
self.out_long = self.long_trailing_stop_price * (1 - self.trailing_stop_percent)
self.out_short = self.short_trailing_stop_price * (1 + self.trailing_stop_percent)
# print('datetime+sig: ',dt,'空头出线',self.out_short)
# print('datetime+sig: ',dt,'多头出线',self.out_long)
# 跟踪出场
if self.out_long > 0:
if (
self.low[0] < self.out_long
and self.pos > 0
and self.sl_long_price > 0
and self.low[0] > self.sl_long_price
):
print(
"--多头止盈出场datetime+sig: ",
dt,
"Trailing stop triggered: Closing position",
"TR",
self.out_long,
"low",
self.low[0],
)
self.close(data=self.data, price=self.data.close[0], size=self.Lots, exectype=bt.Order.Market)
self.long_trailing_stop_price = 0
self.sl_long_price = 0
self.out_long = 0
self.pos = 0
if self.out_short > 0:
if (
self.high[0] > self.out_short
and self.pos < 0
and self.sl_shor_price > 0
and self.high[0] < self.sl_shor_price
):
print(
"--空头止盈出场datetime+sig: ",
dt,
"Trailing stop triggered: Closing position: ",
"TR",
self.out_short,
"high",
self.high[0],
)
self.close(data=self.data, price=self.data.close[0], size=self.Lots, exectype=bt.Order.Market)
self.short_trailing_stop_price = 0
self.sl_shor_price = 0
self.out_shor = 0
self.pos = 0
# 固定止损
self.fixed_stop_loss_L = self.sl_long_price * (1 - self.fixed_stop_loss_percent)
if (
self.sl_long_price > 0
and self.fixed_stop_loss_L > 0
and self.pos > 0
and self.closes[0] < self.fixed_stop_loss_L
):
print(
"--多头止损datetime+sig: ",
dt,
"Fixed stop loss triggered: Closing position",
"SL",
self.fixed_stop_loss_L,
"close",
self.closes[0],
)
self.close(data=self.data, price=self.data.close[0], size=self.Lots, exectype=bt.Order.Market)
self.long_trailing_stop_price = 0
self.sl_long_price = 0
self.out_long = 0
self.pos = 0
self.fixed_stop_loss_S = self.sl_shor_price * (1 + self.fixed_stop_loss_percent)
if (
self.sl_shor_price > 0
and self.fixed_stop_loss_S > 0
and self.pos < 0
and self.closes[0] > self.fixed_stop_loss_S
):
print(
"--空头止损datetime+sig: ",
dt,
"Fixed stop loss triggered: Closing position",
"SL",
self.fixed_stop_loss_S,
"close",
self.closes[0],
)
self.close(data=self.data, price=self.data.close[0], size=self.Lots, exectype=bt.Order.Market)
self.short_trailing_stop_price = 0
self.sl_shor_price = 0
self.out_short = 0
self.pos = 0
# 更新最高价和最低价的列表
self.datetime_list.append(dt)
self.high_list.append(self.data.high[0])
self.low_list.append(self.data.low[0])
self.close_list.append(self.data.close[0])
self.opens_list.append(self.data.open[0])
self.deltas_list.append(self.data.delta[0])
# 计算delta累计
self.delta_cumsum.append(sum(self.deltas_list))
# 将当前行数据添加到 DataFrame
# new_row = {
# 'datetime': dt,
# 'high': self.data.high[0],
# 'low': self.data.low[0],
# 'close': self.data.close[0],
# 'open': self.data.open[0],
# 'delta': self.data.delta[0],
# 'delta_cumsum': sum(self.deltas_list)
# }
# # 使用pandas.concat代替append
# self.df = pd.concat([self.df, pd.DataFrame([new_row])], ignore_index=True)
# # 检查文件是否存在
# csv_file_path = f"output.csv"
# if os.path.exists(csv_file_path):
# # 仅保存最后一行数据
# self.df.tail(1).to_csv(csv_file_path, mode='a', header=False, index=False)
# else:
# # 创建新文件并保存整个DataFrame
# self.df.to_csv(csv_file_path, index=False)
#
if run_kg is False: #
# ————jerome注释增加Boll指标测试
upper, middle, lower = tb.BBANDS(np.array(self.deltas_list), timeperiod=20, nbdevup=2, nbdevdn=2, matype=0)
upper_cum, middle_cum, lower_cum = tb.BBANDS(
np.array(self.delta_cumsum), timeperiod=20, nbdevup=2, nbdevdn=2, matype=0
)
# 增加PPO指标测试
# ppo = tb.PPO(np.array(self.deltas_list))
# PPO_cum = tb.PPO(np.array(self.delta_cumsum))
# 增加MOM指标测试
# mom = tb.MOM(np.array(self.deltas_list), 30)
# mom_cum = tb.MOM(np.array(self.delta_cumsum), 30)
# 增加 MACDFIX指标测试
# macdfix = tb.MACDFIX(np.array(self.deltas_list), 9)
# macdfix_cum = tb.MACDFIX(np.array(self.delta_cumsum), 9)
# 增加 CMO指标测试
# cmo = tb.CMO(np.array(self.deltas_list))
# cmo_cum = tb.CMO(np.array(self.delta_cumsum))
# 增加 APO指标测试
# apo = tb.APO(np.array(self.deltas_list))
# apo_cum = tb.APO(np.array(self.delta_cumsum))
# 增加 WMA指标测试
# wma = tb.WMA(np.array(self.deltas_list))
# wma_cum = tb.WMA(np.array(self.delta_cumsum))
# 增加 WMA指标测试
# ema = tb.EMA(np.array(self.deltas_list))
# ema_cum = tb.EMA(np.array(self.delta_cumsum))
# 增加 T3指标测试(效果非常好)
# t3 = tb.T3(np.array(self.deltas_list))
# t3_cum = tb.T3(np.array(self.delta_cumsum))
# ————jerome注释增加Boll函数测试
# jerome注释self.signal[0] >1 1为堆积信号
# 开多组合= self.rinei_mean>0 and self.closes[0]>self.rinei_mean and self.signal[0] >1 and self.data.delta[0]>middle[-1] and self.delta_cumsum[-1]>middle_cum[-1]#jerome注释self.signal[0] >1 1为堆积信号and self.data.delta[0]>0 and self.delta_cumsum[-1]>2000
# 开空组合= self.rinei_mean>0 and self.closes[0]<self.rinei_mean and self.signal[0] <-1 and self.data.delta[0]<middle[-1] and self.delta_cumsum[-1]<middle_cum[-1]#jerome注释self.signal[0] >1 1为堆积信号and self.data.delta[0]<-0 and self.delta_cumsum[-1]<-2000
开多组合 = (
self.reniei_bop[-1] > 0
and self.signal[0] > 2
and self.data.delta[0] > max(self.deltas_list[-30:-1], default=0) # 1.1 * middle[-1]
and self.delta_cumsum[-1] > max(self.delta_cumsum[-31:-2], default=0) # 1.1 * middle_cum[-1]
# and apo[-1] > 10
# and apo_cum[-1] > 10
)
开空组合 = (
self.reniei_bop[-1] < 0
and self.signal[0] < -2
and self.data.delta[0] < min(self.deltas_list[-30:-1], default=0) # 0.9 * middle[-1]
and self.delta_cumsum[-1] < min(self.delta_cumsum[-31:-2], default=0) # 0.9 * middle_cum[-1]
# and apo[-1] < -10
# and apo_cum[-1] < -10
)
平多条件 = self.pos < 0 and self.signal[0] > 2
平空条件 = self.pos > 0 and self.signal[0] < -2
if self.pos != 1: #
if 平多条件:
# print('datetime+sig: ', dt, 'Fixed stop loss triggered: Closing position', 'SL', self.fixed_stop_loss_S, 'close', self.closes[0])
self.close(data=self.data, price=self.data.close[0], exectype=bt.Order.Market)
self.short_trailing_stop_price = 0
self.sl_shor_price = 0
self.out_short = 0
self.pos = 0
if 开多组合: #
self.buy(data=self.data, price=self.data.close[0], size=1, exectype=bt.Order.Market)
self.pos = 1
self.long_trailing_stop_price = self.low[0]
self.sl_long_price = self.data.open[0]
# print('datetime+sig: ',dt,' sig: ',self.signal[0],'保存多头价格: ',self.long_trailing_stop_price)
if self.pos != -1: #
if 平空条件:
# print('datetime+sig: ', dt, 'Fixed stop loss triggered: Closing position', 'SL', self.fixed_stop_loss_L, 'close', self.closes[0])
self.close(data=self.data, price=self.data.close[0], exectype=bt.Order.Market)
self.long_trailing_stop_price = 0
self.sl_long_price = 0
self.out_long = 0
self.pos = 0
if 开空组合: #
self.sell(data=self.data, price=self.data.close[0], size=1, exectype=bt.Order.Market)
self.pos = -1
self.short_trailing_stop_price = self.high[0]
self.sl_shor_price = self.data.open[0]
# print('datetime+sig: ',dt,' sig: ',self.signal[0],'保存空头价格: ',self.short_trailing_stop_price)
if __name__ == "__main__":
# 公众号松鼠Quant
# 主页www.quant789.com
# 本策略仅作学习交流使用,实盘交易盈亏投资者个人负责!!!
# 版权归松鼠Quant所有禁止转发、转卖源码违者必究。
# 创建Cerebro实例
cerebro = bt.Cerebro()
# 数据
csv_file = r"D:\BaiduNetdiskDownload\主力连续\tick生成的OF数据(5M)\data_rs_merged\中金所\IF888\IF888_rs_2022_5T_back_ofdata_dj.csv" #
png_filepath = r"D:\BaiduNetdiskDownload\主力连续\tick生成的OF数据(5M)\data_rs_merged\中金所\IF888\部分回测报告"
# 从CSV文件加载数据
data = GenericCSV_SIG(
dataname=csv_file,
fromdate=datetime(2022, 1, 1),
todate=datetime(2022, 12, 29),
timeframe=bt.TimeFrame.Minutes,
nullvalue=0.0,
dtformat="%Y-%m-%d %H:%M:%S",
datetime=0,
high=3,
low=4,
open=2,
close=1,
volume=5,
openinterest=None,
sig=6,
delta=8,
)
# 添加数据到Cerebro实例
cerebro.adddata(data)
# 添加策略到Cerebro实例
cerebro.addstrategy(MyStrategy_固定止损_跟踪止盈)
# 添加观察者和分析器到Cerebro实例
# cerebro.addobserver(bt.observers.BuySell)
cerebro.addobserver(bt.observers.Value)
cerebro.addanalyzer(bt.analyzers.Returns, _name="returns")
cerebro.addanalyzer(bt.analyzers.DrawDown, _name="drawdown")
cerebro.addanalyzer(bt.analyzers.TradeAnalyzer, _name="trades")
# cerebro.addanalyzer(bt.analyzers.sharpe, __name_= "sharpe")
初始资金 = 300000
cerebro.broker.setcash(初始资金) # 设置初始资金
# 手续费,单手保证金,合约倍数
cerebro.broker.setcommission(commission=14, margin=150000.0, mult=300) # 回测参数
# 运行回测
result = cerebro.run()
# 获取策略分析器中的结果
analyzer = result[0].analyzers
total_trades = analyzer.trades.get_analysis()["total"]["total"]
winning_trades = analyzer.trades.get_analysis()["won"]["total"]
# 获取TradeAnalyzer分析器的结果
trade_analyzer_result = analyzer.trades.get_analysis()
# 获取总收益额
total_profit = trade_analyzer_result.pnl.net.total
if total_trades > 0:
win_rate = winning_trades / total_trades
else:
win_rate = 0.0
# 打印回测报告
print("回测报告:")
print("期初权益", 初始资金)
print("期末权益", 初始资金 + round(total_profit))
print("盈亏额", round(total_profit))
print("最大回撤率,", round(analyzer.drawdown.get_analysis()["drawdown"], 2), "%")
print("胜率,", round(win_rate * 100, 2), "%")
print("交易次数,", total_trades)
print("盈利次数,", winning_trades)
print("亏损次数,", total_trades - winning_trades)
print("总手续费+滑点,", 手续费汇总)
手续费汇总 = 0
# 保存回测图像文件
plot = cerebro.plot()[0][0]
plot_filename = os.path.splitext(os.path.basename(csv_file))[0] + "ss" + "_plot.png"
# plot_path = os.path.join('部分回测报告', plot_filename)
if not os.path.exists(png_filepath):
# os.mkdir(png_filepath)
os.makedirs(png_filepath)
plot_path = os.path.join(png_filepath, plot_filename)
plot.savefig(plot_path)
# 公众号松鼠Quant
# 主页www.quant789.com
# 本策略仅作学习交流使用,实盘交易盈亏投资者个人负责!!!

View File

@@ -0,0 +1,514 @@
"""
以下是代码的详细说明:
#公众号松鼠Quant
#主页www.quant789.com
#本策略仅作学习交流使用,实盘交易盈亏投资者个人负责!!!
#版权归松鼠Quant所有禁止转发、转卖源码违者必究。
1.
导入必要的模块和库:
backtrader 用于回测功能
datetime 用于处理日期和时间
GenericCSVData 用于从CSV文件加载数据
numpy 用于数值操作
time 用于时间相关操作
matplotlib.pyplot 用于绘图
2. 定义自定义手续费模板MyCommission
继承自bt.CommInfoBase
3.
定义自定义数据源类 GenericCSV_SIG
继承自 GenericCSVData并添加了两个额外的行'sig''delta'
定义了参数 'sig''delta'
4.
定义 MyStrategy_固定止损_跟踪止盈 类:
继承自 bt.Strategybacktrader的基础策略类
定义了两个参数trailing_stop_percent 和 fixed_stop_loss_percent
初始化策略并设置各种变量和指标
实现了 next 方法该方法在数据源的每个新的K线出现时被调用
根据当前K线数据更新跟踪止盈价格
实现了跟踪止盈出场和固定止损出场
根据信号处理多头和空头仓位
在策略执行过程中打印调试信息
5.
if __name__ == "__main__": 代码块:
使用 Cerebro 实例设置回测环境
使用 GenericCSV_SIG 数据源从CSV文件加载数据
将数据源和策略添加到 Cerebro 实例中
添加观察者和分析器以评估性能
设置初始资金和经纪人参数
运行回测并获取结果
打印回测报告,包括收益率、回撤、胜率和交易统计数据
6.使用前事项:
1、主程序中修改ofdata_dj文件地址、png_filepath地址
2、修改clearing_time2_start、clearing_time2_stop
3、修改交易参数:lots、跟踪止损百分、固定止损百分比、duiji、cout_delta、delta
4、修改资金参数:初始资金;回测参数:回测时间段、佣金、单边保证金、手续费;
"""
import backtrader as bt
from datetime import datetime
from datetime import time as s_time
from backtrader.feeds import GenericCSVData
import numpy as np
import pandas as pd
import time
import matplotlib.pyplot as plt
import os
import talib as tb # jerom注释 增加talib库
手续费汇总 = 0
class GenericCSV_SIG(GenericCSVData):
# 从基类继承,添加一个 'sig'delta
lines = ("sig", "delta")
# 添加参数为从基类继承的参数
params = (("sig", 6), ("delta", 8))
class MyStrategy_固定止损_跟踪止盈(bt.Strategy):
params = (
("trailing_stop_percent", 0.010), # 跟踪止盈百分比
("fixed_stop_loss_percent", 0.02), # 固定止损百分比
)
def __init__(self):
self.Lots = 1 # 下单手数
self.signal = self.datas[0].sig # 使用sig字段作为策略的信号字段
self.delta = self.datas[0].delta
# 获取数据序列别名列表
line_aliases = self.datas[0].getlinealiases()
self.pos = 0
print(line_aliases)
self.high = self.datas[0].high
self.low = self.datas[0].low
self.closes = self.datas[0].close
self.open = self.datas[0].open
self.trailing_stop_percent = self.params.trailing_stop_percent
self.short_trailing_stop_price = 0
self.long_trailing_stop_price = 0
self.fixed_stop_loss_percent = self.params.fixed_stop_loss_percent
self.sl_long_price = 0
self.sl_shor_price = 0
self.out_long = 0
# 240884432
self.out_short = 0
self.rinei_ma = []
self.renei_high_ma = []
self.renei_low_ma = []
self.rinei_mean = 0
self.reniei_sar = []
self.datetime_list = []
self.high_list = []
self.low_list = []
self.close_list = []
self.opens_list = []
self.deltas_list = []
self.delta_cumsum = []
self.barN = 0
self.df = pd.DataFrame(columns=["datetime", "high", "low", "close", "open", "delta", "delta_cumsum"])
self.trader_df = pd.DataFrame(columns=["open", "high", "low", "close", "volume", "openInterest", "delta"])
def log(self, txt, dt=None):
"""可选,构建策略打印日志的函数:可用于打印订单记录或交易记录等"""
dt = dt or self.datas[0].datetime.date(0)
print("%s, %s" % (dt.isoformat(), txt))
def notify_order(self, order):
# 未被处理的订单
if order.status in [order.Submitted, order.Accepted]:
return
# 已经处理的订单
if order.status in [order.Completed, order.Canceled, order.Margin]:
global 手续费汇总
if order.isbuy():
手续费汇总 += order.executed.comm
self.log(
"BUY EXECUTED, 订单编号:%.0f,成交价格: %.2f, 手续费滑点:%.2f, 成交量: %.2f, 品种: %s,手续费汇总:%.2f"
% (
order.ref, # 订单编号
order.executed.price, # 成交价
order.executed.comm, # 佣金
order.executed.size, # 成交量
order.data._name, # 品种名称
手续费汇总,
)
)
else: # Sell
手续费汇总 += order.executed.comm
self.log(
"SELL EXECUTED, 订单编号:%.0f,成交价格: %.2f, 手续费滑点:%.2f, 成交量: %.2f, 品种: %s,手续费汇总:%.2f"
% (
order.ref,
order.executed.price,
order.executed.comm,
order.executed.size,
order.data._name,
手续费汇总,
)
)
def next(self):
# 公众号松鼠Quant
# 主页www.quant789.com
# 本策略仅作学习交流使用,实盘交易盈亏投资者个人负责!!!
# 版权归松鼠Quant所有禁止转发、转卖源码违者必究。
# bar线计数初始化
self.barN += 1
position = self.getposition(self.datas[0]).size
# 时间轴
dt = bt.num2date(self.data.datetime[0])
# 更新跟踪止损价格
def 每日重置数据():
# 获取当前时间
current_time = dt.time()
# print(current_time)
# 设置清仓操作的时间范围114:55到15:00
clearing_time1_start = s_time(14, 55)
clearing_time1_end = s_time(15, 0)
# 设置清仓操作的时间范围200:55到01:00
clearing_time2_start = s_time(2, 25)
clearing_time2_end = s_time(2, 30)
# 创建一个标志变量
clearing_executed = False
if clearing_time1_start <= current_time <= clearing_time1_end and not clearing_executed:
clearing_executed = True # 设置标志变量为已执行
self.rinei_ma = []
self.renei_high_ma = []
self.renei_low_ma = []
self.delta_cumsum = []
self.deltas_list = []
elif clearing_time2_start <= current_time <= clearing_time2_end and not clearing_executed:
clearing_executed = True # 设置标志变量为已执行
self.rinei_ma = []
self.renei_high_ma = []
self.renei_low_ma = []
self.delta_cumsum = []
self.deltas_list = []
# 如果不在任何时间范围内,可以执行其他操作
else:
self.rinei_ma.append(self.closes[0])
self.renei_high_ma.append(self.high[0])
self.renei_low_ma.append(self.low[0])
self.rinei_mean = np.mean(self.rinei_ma)
self.reniei_sar = tb.SAR(np.array(self.renei_high_ma), np.array(self.renei_low_ma), 0.02, 0.2)
# self.delta_cumsum=[]
# self.deltas_list=[]
# print('rinei_ma',self.rinei_ma)
clearing_executed = False
pass
return clearing_executed
run_kg = 每日重置数据()
# 过滤成交量为0或小于0
if self.data.volume[0] <= 0:
return
# print(f'volume,{self.data.volume[0]}')
if self.long_trailing_stop_price > 0 and self.pos > 0:
# print('datetime+sig: ',dt,'旧多头出线',self.long_trailing_stop_price,'low',self.low[0])
self.long_trailing_stop_price = (
self.low[0] if self.long_trailing_stop_price < self.low[0] else self.long_trailing_stop_price
)
# print('datetime+sig: ',dt,'多头出线',self.long_trailing_stop_price)
if self.short_trailing_stop_price > 0 and self.pos < 0:
# print('datetime+sig: ',dt,'旧空头出线',self.short_trailing_stop_price,'high',self.high[0])
self.short_trailing_stop_price = (
self.high[0] if self.high[0] < self.short_trailing_stop_price else self.short_trailing_stop_price
)
# print('datetime+sig: ',dt,'空头出线',self.short_trailing_stop_price)
self.out_long = self.long_trailing_stop_price * (1 - self.trailing_stop_percent)
self.out_short = self.short_trailing_stop_price * (1 + self.trailing_stop_percent)
# print('datetime+sig: ',dt,'空头出线',self.out_short)
# print('datetime+sig: ',dt,'多头出线',self.out_long)
# 跟踪出场
if self.out_long > 0:
if (
self.low[0] < self.out_long
and self.pos > 0
and self.sl_long_price > 0
and self.low[0] > self.sl_long_price
):
print(
"--多头止盈出场datetime+sig: ",
dt,
"Trailing stop triggered: Closing position",
"TR",
self.out_long,
"low",
self.low[0],
)
self.close(data=self.data, price=self.data.close[0], size=self.Lots, exectype=bt.Order.Market)
self.long_trailing_stop_price = 0
self.sl_long_price = 0
self.out_long = 0
self.pos = 0
if self.out_short > 0:
if (
self.high[0] > self.out_short
and self.pos < 0
and self.sl_shor_price > 0
and self.high[0] < self.sl_shor_price
):
print(
"--空头止盈出场datetime+sig: ",
dt,
"Trailing stop triggered: Closing position: ",
"TR",
self.out_short,
"high",
self.high[0],
)
self.close(data=self.data, price=self.data.close[0], size=self.Lots, exectype=bt.Order.Market)
self.short_trailing_stop_price = 0
self.sl_shor_price = 0
self.out_shor = 0
self.pos = 0
# 固定止损
self.fixed_stop_loss_L = self.sl_long_price * (1 - self.fixed_stop_loss_percent)
if (
self.sl_long_price > 0
and self.fixed_stop_loss_L > 0
and self.pos > 0
and self.closes[0] < self.fixed_stop_loss_L
):
print(
"--多头止损datetime+sig: ",
dt,
"Fixed stop loss triggered: Closing position",
"SL",
self.fixed_stop_loss_L,
"close",
self.closes[0],
)
self.close(data=self.data, price=self.data.close[0], size=self.Lots, exectype=bt.Order.Market)
self.long_trailing_stop_price = 0
self.sl_long_price = 0
self.out_long = 0
self.pos = 0
self.fixed_stop_loss_S = self.sl_shor_price * (1 + self.fixed_stop_loss_percent)
if (
self.sl_shor_price > 0
and self.fixed_stop_loss_S > 0
and self.pos < 0
and self.closes[0] > self.fixed_stop_loss_S
):
print(
"--空头止损datetime+sig: ",
dt,
"Fixed stop loss triggered: Closing position",
"SL",
self.fixed_stop_loss_S,
"close",
self.closes[0],
)
self.close(data=self.data, price=self.data.close[0], size=self.Lots, exectype=bt.Order.Market)
self.short_trailing_stop_price = 0
self.sl_shor_price = 0
self.out_short = 0
self.pos = 0
# 更新最高价和最低价的列表
self.datetime_list.append(dt)
self.high_list.append(self.data.high[0])
self.low_list.append(self.data.low[0])
self.close_list.append(self.data.close[0])
self.opens_list.append(self.data.open[0])
self.deltas_list.append(self.data.delta[0])
# 计算delta累计
self.delta_cumsum.append(sum(self.deltas_list))
# 将当前行数据添加到 DataFrame
# new_row = {
# 'datetime': dt,
# 'high': self.data.high[0],
# 'low': self.data.low[0],
# 'close': self.data.close[0],
# 'open': self.data.open[0],
# 'delta': self.data.delta[0],
# 'delta_cumsum': sum(self.deltas_list)
# }
# # 使用pandas.concat代替append
# self.df = pd.concat([self.df, pd.DataFrame([new_row])], ignore_index=True)
# # 检查文件是否存在
# csv_file_path = f"output.csv"
# if os.path.exists(csv_file_path):
# # 仅保存最后一行数据
# self.df.tail(1).to_csv(csv_file_path, mode='a', header=False, index=False)
# else:
# # 创建新文件并保存整个DataFrame
# self.df.to_csv(csv_file_path, index=False)
#
if run_kg == False: #
# ————jerome注释增加Boll函数测试
upper, middle, lower = tb.BBANDS(np.array(self.deltas_list), timeperiod=5, nbdevup=2, nbdevdn=2, matype=0)
upper_cum, middle_cum, lower_cum = tb.BBANDS(
np.array(self.delta_cumsum), timeperiod=5, nbdevup=2, nbdevdn=2, matype=0
)
# ————jerome注释增加Boll函数测试
# jerome注释self.signal[0] >1 1为堆积信号
# 开多组合= self.rinei_mean>0 and self.closes[0]>self.rinei_mean and self.signal[0] >1 and self.data.delta[0]>middle[-1] and self.delta_cumsum[-1]>middle_cum[-1]#jerome注释self.signal[0] >1 1为堆积信号and self.data.delta[0]>0 and self.delta_cumsum[-1]>2000
# 开空组合= self.rinei_mean>0 and self.closes[0]<self.rinei_mean and self.signal[0] <-1 and self.data.delta[0]<middle[-1] and self.delta_cumsum[-1]<middle_cum[-1]#jerome注释self.signal[0] >1 1为堆积信号and self.data.delta[0]<-0 and self.delta_cumsum[-1]<-2000
开多组合 = (
self.reniei_sar[-1] > self.closes[0]
and self.signal[0] > 3
and self.data.delta[0] > 700000
and self.delta_cumsum[-1] > 700000
)
开空组合 = (
self.reniei_sar[-1] < self.closes[0]
and self.signal[0] < -3
and self.data.delta[0] < -700000
and self.delta_cumsum[-1] < -700000
)
平多条件 = self.pos < 0 and self.signal[0] > 3
平空条件 = self.pos > 0 and self.signal[0] < -3
if self.pos != 1: #
if 平多条件:
# print('datetime+sig: ', dt, 'Fixed stop loss triggered: Closing position', 'SL', self.fixed_stop_loss_S, 'close', self.closes[0])
self.close(data=self.data, price=self.data.close[0], exectype=bt.Order.Market)
self.short_trailing_stop_price = 0
self.sl_shor_price = 0
self.out_short = 0
self.pos = 0
if 开多组合: #
self.buy(data=self.data, price=self.data.close[0], size=1, exectype=bt.Order.Market)
self.pos = 1
self.long_trailing_stop_price = self.low[0]
self.sl_long_price = self.data.open[0]
# print('datetime+sig: ',dt,' sig: ',self.signal[0],'保存多头价格: ',self.long_trailing_stop_price)
if self.pos != -1: #
if 平空条件:
# print('datetime+sig: ', dt, 'Fixed stop loss triggered: Closing position', 'SL', self.fixed_stop_loss_L, 'close', self.closes[0])
self.close(data=self.data, price=self.data.close[0], exectype=bt.Order.Market)
self.long_trailing_stop_price = 0
self.sl_long_price = 0
self.out_long = 0
self.pos = 0
if 开空组合: #
self.sell(data=self.data, price=self.data.close[0], size=1, exectype=bt.Order.Market)
self.pos = -1
self.short_trailing_stop_price = self.high[0]
self.sl_shor_price = self.data.open[0]
# print('datetime+sig: ',dt,' sig: ',self.signal[0],'保存空头价格: ',self.short_trailing_stop_price)
if __name__ == "__main__":
# 公众号松鼠Quant
# 主页www.quant789.com
# 本策略仅作学习交流使用,实盘交易盈亏投资者个人负责!!!
# 版权归松鼠Quant所有禁止转发、转卖源码违者必究。
# 创建Cerebro实例
cerebro = bt.Cerebro()
# 数据
csv_file = r"D:\BaiduNetdiskDownload\主力连续\tick生成的OF数据(5M)\data_rs_merged\中金所\IM888\IM888_rs_2022_5T_back_ofdata_dj.csv" #
png_filepath = r"D:\BaiduNetdiskDownload\主力连续\tick生成的OF数据(5M)\data_rs_merged\中金所\IM888\部分回测报告"
# 从CSV文件加载数据
data = GenericCSV_SIG(
dataname=csv_file,
fromdate=datetime(2022, 1, 1),
todate=datetime(2022, 12, 29),
timeframe=bt.TimeFrame.Minutes,
nullvalue=0.0,
dtformat="%Y-%m-%d %H:%M:%S",
datetime=0,
high=3,
low=4,
open=2,
close=1,
volume=5,
openinterest=None,
sig=6,
delta=8,
)
# 添加数据到Cerebro实例
cerebro.adddata(data)
# 添加策略到Cerebro实例
cerebro.addstrategy(MyStrategy_固定止损_跟踪止盈)
# 添加观察者和分析器到Cerebro实例
# cerebro.addobserver(bt.observers.BuySell)
cerebro.addobserver(bt.observers.Value)
cerebro.addanalyzer(bt.analyzers.Returns, _name="returns")
cerebro.addanalyzer(bt.analyzers.DrawDown, _name="drawdown")
cerebro.addanalyzer(bt.analyzers.TradeAnalyzer, _name="trades")
# cerebro.addanalyzer(bt.analyzers.sharpe, __name_= "sharpe")
初始资金 = 300000
cerebro.broker.setcash(初始资金) # 设置初始资金
# 手续费,单手保证金,合约倍数
cerebro.broker.setcommission(commission=14, margin=150000.0, mult=300) # 回测参数
# 运行回测
result = cerebro.run()
# 获取策略分析器中的结果
analyzer = result[0].analyzers
total_trades = analyzer.trades.get_analysis()["total"]["total"]
winning_trades = analyzer.trades.get_analysis()["won"]["total"]
# 获取TradeAnalyzer分析器的结果
trade_analyzer_result = analyzer.trades.get_analysis()
# 获取总收益额
total_profit = trade_analyzer_result.pnl.net.total
if total_trades > 0:
win_rate = winning_trades / total_trades
else:
win_rate = 0.0
# 打印回测报告
print("回测报告:")
print("期初权益", 初始资金)
print("期末权益", 初始资金 + round(total_profit))
print("盈亏额", round(total_profit))
print("最大回撤率,", round(analyzer.drawdown.get_analysis()["drawdown"], 2), "%")
print("胜率,", round(win_rate * 100, 2), "%")
print("交易次数,", total_trades)
print("盈利次数,", winning_trades)
print("亏损次数,", total_trades - winning_trades)
print("总手续费+滑点,", 手续费汇总)
手续费汇总 = 0
# 保存回测图像文件
plot = cerebro.plot()[0][0]
plot_filename = os.path.splitext(os.path.basename(csv_file))[0] + "ss" + "_plot.png"
# plot_path = os.path.join('部分回测报告', plot_filename)
if not os.path.exists(png_filepath):
# os.mkdir(png_filepath)
os.makedirs(png_filepath)
plot_path = os.path.join(png_filepath, plot_filename)
plot.savefig(plot_path)
# 公众号松鼠Quant
# 主页www.quant789.com
# 本策略仅作学习交流使用,实盘交易盈亏投资者个人负责!!!

View File

@@ -0,0 +1,679 @@
"""
以下是代码的详细说明:
1.
导入必要的模块和库:
backtrader 用于回测功能
datetime 用于处理日期和时间
GenericCSVData 用于从CSV文件加载数据
numpy 用于数值操作
time 用于时间相关操作
matplotlib.pyplot 用于绘图
2. 定义自定义手续费模板MyCommission
继承自bt.CommInfoBase
3.
定义自定义数据源类 GenericCSV_SIG
继承自 GenericCSVData并添加了两个额外的行'sig''delta'
定义了参数 'sig''delta'
4.
定义 MyStrategy_固定止损_跟踪止盈 类:
继承自 bt.Strategybacktrader的基础策略类
定义了两个参数trailing_stop_percent 和 fixed_stop_loss_percent
初始化策略并设置各种变量和指标
实现了 next 方法该方法在数据源的每个新的K线出现时被调用
根据当前K线数据更新跟踪止盈价格
实现了跟踪止盈出场和固定止损出场
根据信号处理多头和空头仓位
在策略执行过程中打印调试信息
5.
if __name__ == "__main__": 代码块:
使用 Cerebro 实例设置回测环境
使用 GenericCSV_SIG 数据源从CSV文件加载数据
将数据源和策略添加到 Cerebro 实例中
添加观察者和分析器以评估性能
设置初始资金和经纪人参数
运行回测并获取结果
打印回测报告,包括收益率、回撤、胜率和交易统计数据
6.使用前事项:
1、主程序中修改ofdata_dj文件地址、png_filepath地址
2、修改clearing_time2_start、clearing_time2_stop
3、修改交易参数:lots、跟踪止损百分、固定止损百分比、duiji、cout_delta、delta
4、修改资金参数:初始资金;回测参数:回测时间段、佣金、单边保证金、手续费;
"""
import backtrader as bt
from datetime import datetime, timedelta
from datetime import time as s_time
from backtrader.feeds import GenericCSVData
import numpy as np
import pandas as pd
import os
import matplotlib.pyplot as plt
import talib as tb # jerom注释 增加talib库
# import akshare as ak
# 下面是需要设置的参数.其他需要设置参数在函数中:每日重置数据时间、回测开始时间、结束时间、初始资金、手续费,单手保证金,合约倍数
手续费汇总 = 0
trailing_stop_value = 0.02
fixed_stop_loss_value = 0.01
deltas_windows = 240
deltas_cum_windows = 240
duji_value = 2
csv_file_path = r"E:\of_data\主力连续\tick生成的OF数据(5M)\data_rs_merged\中金所\IM888\IM888_rs_2023_5T_back_ofdata_dj.csv"
png_file_path = (
r"E:\of_data\主力连续\tick生成的OF数据(5M)\data_rs_merged\中金所\IM888\部分回测报告"
)
start_date = datetime(2023, 1, 1)
end_date = datetime(2023, 12, 31)
回测资金 = 3000000
单手手续费 = 60
单手保证金 = 15000
交易乘率 = 300
class GenericCSV_SIG(GenericCSVData):
# 从基类继承,添加一个 'sig'delta
lines = ("sig", "delta")
# 添加参数为从基类继承的参数
params = (("sig", 6), ("delta", 8))
# jerome注释增加
def ultimate_smoother(price, period):
# 初始化变量
a1 = np.exp(-1.414 * np.pi / period)
b1 = 2 * a1 * np.cos(1.414 * 180 / period)
c2 = b1
c3 = -a1 * a1
c1 = (1 + c2 - c3) / 4
# 准备输出结果的序列
us = np.zeros(len(price))
# 计算 Ultimate Smoother
for i in range(len(price)):
if i < 4:
us[i] = price[i]
else:
us[i] = (
(1 - c1) * price[i]
+ (2 * c1 - c2) * price[i - 1]
- (c1 + c3) * price[i - 2]
+ c2 * us[i - 1]
+ c3 * us[i - 2]
)
return us
class MyStrategy_固定止损_跟踪止盈(bt.Strategy):
params = (
("trailing_stop_percent", trailing_stop_value), # 跟踪止盈百分比
("fixed_stop_loss_percent", fixed_stop_loss_value), # 固定止损百分比
)
def __init__(self):
self.Lots = 1 # 下单手数
self.signal = self.datas[0].sig # 使用sig字段作为策略的信号字段
self.delta = self.datas[0].delta
# 获取数据序列别名列表
line_aliases = self.datas[0].getlinealiases()
self.pos = 0
print(line_aliases)
self.high = self.datas[0].high
self.low = self.datas[0].low
self.closes = self.datas[0].close
self.open = self.datas[0].open
self.trailing_stop_percent = self.params.trailing_stop_percent
self.short_trailing_stop_price = 0
self.long_trailing_stop_price = 0
self.fixed_stop_loss_percent = self.params.fixed_stop_loss_percent
self.sl_long_price = 0
self.sl_shor_price = 0
self.out_long = 0
self.ultimate_smoother_value = []
self.out_short = 0
self.rinei_ma = []
self.rinei_open_ma = []
self.rinei_high_ma = []
self.rinei_low_ma = []
self.rinei_mean = 0
self.rinei_T3 = []
self.datetime_list = []
self.high_list = []
self.low_list = []
self.close_list = []
self.opens_list = []
self.deltas_list = []
self.delta_cumsum = []
self.duiji_list = []
self.barN = 0
self.df = pd.DataFrame(
columns=[
"datetime",
"high",
"low",
"close",
"open",
"delta",
"delta_cumsum",
]
)
self.trader_df = pd.DataFrame(
columns=["open", "high", "low", "close", "volume", "openInterest", "delta"]
)
def log(self, txt, dt=None):
"""可选,构建策略打印日志的函数:可用于打印订单记录或交易记录等"""
dt = dt or self.datas[0].datetime.date(0)
print("%s, %s" % (dt.isoformat(), txt))
def notify_order(self, order):
# 未被处理的订单
if order.status in [order.Submitted, order.Accepted]:
return
# 已经处理的订单
if order.status in [order.Completed, order.Canceled, order.Margin]:
global 手续费汇总
if order.isbuy():
手续费汇总 += order.executed.comm
self.log(
"BUY EXECUTED, 订单编号:%.0f,成交价格: %.2f, 手续费滑点:%.2f, 成交量: %.2f, 品种: %s,手续费汇总:%.2f"
% (
order.ref, # 订单编号
order.executed.price, # 成交价
order.executed.comm, # 佣金
order.executed.size, # 成交量
order.data._name, # 品种名称
手续费汇总,
)
)
else: # Sell
手续费汇总 += order.executed.comm
self.log(
"SELL EXECUTED, 订单编号:%.0f,成交价格: %.2f, 手续费滑点:%.2f, 成交量: %.2f, 品种: %s,手续费汇总:%.2f"
% (
order.ref,
order.executed.price,
order.executed.comm,
order.executed.size,
order.data._name,
手续费汇总,
)
)
def next(self):
# bar线计数初始化
self.barN += 1
# position = self.getposition(self.datas[0]).size
# 时间轴
dt = bt.num2date(self.data.datetime[0])
# 更新跟踪止损价格
def 每日重置数据():
# 获取当前时间
current_time = dt.time()
# print(current_time)
# 设置清仓操作的时间范围114:55到15:00
clearing_time1_start = s_time(14, 55)
clearing_time1_end = s_time(15, 0)
# 设置清仓操作的时间范围200:55到01:00
clearing_time2_start = s_time(2, 25)
clearing_time2_end = s_time(2, 30)
# 创建一个标志变量
clearing_executed = False
if (
clearing_time1_start <= current_time <= clearing_time1_end
and not clearing_executed
):
clearing_executed = True # 设置标志变量为已执行
self.rinei_ma = []
self.rinei_open_ma = []
self.rinei_high_ma = []
self.rinei_low_ma = []
self.delta_cumsum = []
self.deltas_list = []
self.duiji_list = []
elif (
clearing_time2_start <= current_time <= clearing_time2_end
and not clearing_executed
):
clearing_executed = True # 设置标志变量为已执行
self.rinei_ma = []
self.rinei_open_ma = []
self.rinei_high_ma = []
self.rinei_low_ma = []
self.delta_cumsum = []
self.deltas_list = []
self.duiji_list = []
# 如果不在任何时间范围内,可以执行其他操作
else:
self.rinei_open_ma.append(self.open[0])
self.rinei_ma.append(self.closes[0])
self.rinei_high_ma.append(self.high[0])
self.rinei_low_ma.append(self.low[0])
self.rinei_mean = np.mean(self.rinei_ma)
# self.rinei_T3 = tb.HT_TRENDLINE(np.array(self.rinei_ma),timeperiod=5)
self.rinei_T3 = tb.T3(
np.array(self.rinei_ma), 3
) # , timeperiod=5, vfactor=0.7
# self.riniei_bop = tb.BOP(
# np.array(self.rinei_open_ma),
# np.array(self.rinei_high_ma),
# np.array(self.rinei_low_ma),
# np.array(self.rinei_ma),
# )
# self.delta_cumsum=[]
# self.deltas_list=[]
# print('rinei_ma',self.rinei_ma)
clearing_executed = False
pass
return clearing_executed
run_kg = 每日重置数据()
# 过滤成交量为0或小于0
if self.data.volume[0] <= 0:
return
# print(f'volume,{self.data.volume[0]}')
if self.long_trailing_stop_price > 0 and self.pos > 0:
# print('datetime+sig: ',dt,'旧多头出线',self.long_trailing_stop_price,'low',self.low[0])
self.long_trailing_stop_price = (
self.low[0]
if self.long_trailing_stop_price < self.low[0]
else self.long_trailing_stop_price
)
# print('datetime+sig: ',dt,'多头出线',self.long_trailing_stop_price)
if self.short_trailing_stop_price > 0 and self.pos < 0:
# print('datetime+sig: ',dt,'旧空头出线',self.short_trailing_stop_price,'high',self.high[0])
self.short_trailing_stop_price = (
self.high[0]
if self.high[0] < self.short_trailing_stop_price
else self.short_trailing_stop_price
)
# print('datetime+sig: ',dt,'空头出线',self.short_trailing_stop_price)
# self.out_long = self.long_trailing_stop_price * (
# 1 - self.trailing_stop_percent)
# self.out_short = self.short_trailing_stop_price * (
# 1 + self.trailing_stop_percent)
self.ultimate_smoother_value = ultimate_smoother(self.closes, 20)
self.out_long = self.ultimate_smoother_value[-1]
self.out_short = self.ultimate_smoother_value[-1]
# print('datetime+sig: ',dt,'空头出线',self.out_short)
# print('datetime+sig: ',dt,'多头出线',self.out_long)
# 跟踪出场
if self.out_long > 0:
if (
self.low[0] < self.out_long
and self.pos > 0
and self.sl_long_price > 0
and self.low[0] > self.sl_long_price
):
print(
"--多头止盈出场datetime+sig: ",
dt,
"Trailing stop triggered: Closing position",
"TR",
self.out_long,
"low",
self.low[0],
)
self.close(
data=self.data,
price=self.data.close[0],
size=self.Lots,
exectype=bt.Order.Market,
)
self.long_trailing_stop_price = 0
self.sl_long_price = 0
self.out_long = 0
self.pos = 0
if self.out_short > 0:
if (
self.high[0] > self.out_short
and self.pos < 0
and self.sl_shor_price > 0
and self.high[0] < self.sl_shor_price
):
print(
"--空头止盈出场datetime+sig: ",
dt,
"Trailing stop triggered: Closing position: ",
"TR",
self.out_short,
"high",
self.high[0],
)
self.close(
data=self.data,
price=self.data.close[0],
size=self.Lots,
exectype=bt.Order.Market,
)
self.short_trailing_stop_price = 0
self.sl_shor_price = 0
self.out_shor = 0
self.pos = 0
# 固定止损
self.fixed_stop_loss_L = self.sl_long_price * (1 - self.fixed_stop_loss_percent)
if (
self.sl_long_price > 0
and self.fixed_stop_loss_L > 0
and self.pos > 0
and self.closes[0] < self.fixed_stop_loss_L
):
print(
"--多头止损datetime+sig: ",
dt,
"Fixed stop loss triggered: Closing position",
"SL",
self.fixed_stop_loss_L,
"close",
self.closes[0],
)
self.close(
data=self.data,
price=self.data.close[0],
size=self.Lots,
exectype=bt.Order.Market,
)
self.long_trailing_stop_price = 0
self.sl_long_price = 0
self.out_long = 0
self.pos = 0
self.fixed_stop_loss_S = self.sl_shor_price * (1 + self.fixed_stop_loss_percent)
if (
self.sl_shor_price > 0
and self.fixed_stop_loss_S > 0
and self.pos < 0
and self.closes[0] > self.fixed_stop_loss_S
):
print(
"--空头止损datetime+sig: ",
dt,
"Fixed stop loss triggered: Closing position",
"SL",
self.fixed_stop_loss_S,
"close",
self.closes[0],
)
self.close(
data=self.data,
price=self.data.close[0],
size=self.Lots,
exectype=bt.Order.Market,
)
self.short_trailing_stop_price = 0
self.sl_shor_price = 0
self.out_short = 0
self.pos = 0
# 更新最高价和最低价的列表
self.datetime_list.append(dt)
self.high_list.append(self.data.high[0])
self.low_list.append(self.data.low[0])
self.close_list.append(self.data.close[0])
self.opens_list.append(self.data.open[0])
self.deltas_list.append(self.data.delta[0])
# 计算delta累计
self.delta_cumsum.append(sum(self.deltas_list[-20:]))
self.duiji_list.append(self.data.sig[0])
# 将当前行数据添加到 DataFrame
# new_row = {
# 'datetime': dt,
# 'high': self.data.high[0],
# 'low': self.data.low[0],
# 'close': self.data.close[0],
# 'open': self.data.open[0],
# 'delta': self.data.delta[0],
# 'delta_cumsum': sum(self.deltas_list)
# }
# # 使用pandas.concat代替append
# self.df = pd.concat([self.df, pd.DataFrame([new_row])], ignore_index=True)
# # 检查文件是否存在
# csv_file_path = f"output.csv"
# if os.path.exists(csv_file_path):
# # 仅保存最后一行数据
# self.df.tail(1).to_csv(csv_file_path, mode='a', header=False, index=False)
# else:
# # 创建新文件并保存整个DataFrame
# self.df.to_csv(csv_file_path, index=False)
#
if run_kg is False:
# ————jerome注释增加指标测试
# 增加Boll指标测试
# upper, middle, lower = tb.BBANDS(np.array(self.deltas_list), timeperiod=20, nbdevup=2, nbdevdn=2, matype=0)
# upper_cum, middle_cum, lower_cum = tb.BBANDS(
# np.array(self.delta_cumsum), timeperiod=20, nbdevup=2, nbdevdn=2, matype=0
# )
# 增加PPO指标测试
# ppo = tb.PPO(np.array(self.deltas_list))
# PPO_cum = tb.PPO(np.array(self.delta_cumsum))
# 增加MOM指标测试
# mom = tb.MOM(np.array(self.deltas_list), 30)
# mom_cum = tb.MOM(np.array(self.delta_cumsum), 30)
# 增加 MACDFIX指标测试
# macdfix = tb.MACDFIX(np.array(self.deltas_list), 9)
# macdfix_cum = tb.MACDFIX(np.array(self.delta_cumsum), 9)
# 增加 CMO指标测试
# cmo = tb.CMO(np.array(self.deltas_list))
# cmo_cum = tb.CMO(np.array(self.delta_cumsum))
# 增加 APO指标测试
# apo = tb.APO(np.array(self.deltas_list))
# apo_cum = tb.APO(np.array(self.delta_cumsum))
# 增加 WMA指标测试
# wma = tb.WMA(np.array(self.deltas_list))
# wma_cum = tb.WMA(np.array(self.delta_cumsum))
# 增加 WMA指标测试
# ema = tb.EMA(np.array(self.deltas_list))
# ema_cum = tb.EMA(np.array(self.delta_cumsum))
# 增加 T3指标测试(效果非常好)
t3 = tb.T3(np.array(self.deltas_list))
t3_cum = tb.T3(np.array(self.delta_cumsum))
# futures_main_sina_hist = ak.futures_main_sina(
# symbol="IM0", start_date=start_date, end_date="20231231"
# )
# futures_main_sina_hist["5day_ma"] = (
# futures_main_sina_hist["收盘价"].rolling(window=5).mean()
# )
# ——jerome注释self.signal[0] >1 1为堆积信号
# 开多组合= self.rinei_mean>0 and self.closes[0]>self.rinei_mean and self.signal[0] >1 and self.data.delta[0]>middle[-1] and self.delta_cumsum[-1]>middle_cum[-1]#jerome注释self.signal[0] >1 1为堆积信号and self.data.delta[0]>0 and self.delta_cumsum[-1]>2000
# 开空组合= self.rinei_mean>0 and self.closes[0]<self.rinei_mean and self.signal[0] <-1 and self.data.delta[0]<middle[-1] and self.delta_cumsum[-1]<middle_cum[-1]#jerome注释self.signal[0] >1 1为堆积信号and self.data.delta[0]<-0 and self.delta_cumsum[-1]<-2000
开多组合 = (
self.closes[0] > self.rinei_T3[-1]
# futures_main_sina_hist["收盘价"].iloc[0]
# > futures_main_sina_hist["5day_ma"].iloc[-1]
# self.riniei_bop[-1] > 0
and self.signal[0]
> max(self.duiji_list[-deltas_windows:-1], default=0) # duji_value
and self.data.delta[0] > t3[-1] # max(
# self.deltas_list[-deltas_windows:-1], default=0
# ) # 1.1 * middle[-1]
and self.delta_cumsum[-1] > t3_cum[-1] # max(
# self.delta_cumsum[-deltas_cum_windows - 1 : -2], default=0
# ) # 1.1 * middle_cum[-1]
# and apo[-1] > 10
# and apo_cum[-1] > 10
)
开空组合 = (
self.closes[0] < self.rinei_T3[-1]
# self.riniei_bop[-1] < 0
# futures_main_sina_hist["收盘价"].iloc[0]
# < futures_main_sina_hist["5day_ma"].iloc[-1]
and self.signal[0]
< min(self.duiji_list[-deltas_windows:-1], default=0) # -duji_value
and self.data.delta[0] < t3[-1] # min(
# self.deltas_list[-deltas_windows:-1], default=0
# ) # 0.9 * middle[-1]
and self.delta_cumsum[-1] < t3_cum[-1] # min(
# self.delta_cumsum[-deltas_cum_windows - 1 : -2], default=0
# ) # 0.9 * middle_cum[-1]
# and apo[-1] < -10
# and apo_cum[-1] < -10
)
平空条件 = self.pos < 0 and self.signal[0] > max(
self.duiji_list[-deltas_windows:-1], default=0
) # duji_value
平多条件 = self.pos > 0 and self.signal[0] < min(
self.duiji_list[-deltas_windows:-1], default=0
) # -duji_value
if self.pos != 1: #
if 平空条件:
# print('datetime+sig: ', dt, 'Fixed stop loss triggered: Closing position', 'SL', self.fixed_stop_loss_S, 'close', self.closes[0])
self.close(
data=self.data,
price=self.data.close[0],
exectype=bt.Order.Market,
)
self.short_trailing_stop_price = 0
self.sl_shor_price = 0
self.out_short = 0
self.pos = 0
if 开多组合: #
self.buy(
data=self.data,
price=self.data.close[0],
size=1,
exectype=bt.Order.Market,
)
self.pos = 1
self.long_trailing_stop_price = self.low[0]
self.sl_long_price = self.data.open[0]
# print('datetime+sig: ',dt,' sig: ',self.signal[0],'保存多头价格: ',self.long_trailing_stop_price)
if self.pos != -1: #
if 平多条件:
# print('datetime+sig: ', dt, 'Fixed stop loss triggered: Closing position', 'SL', self.fixed_stop_loss_L, 'close', self.closes[0])
self.close(
data=self.data,
price=self.data.close[0],
exectype=bt.Order.Market,
)
self.long_trailing_stop_price = 0
self.sl_long_price = 0
self.out_long = 0
self.pos = 0
if 开空组合: #
self.sell(
data=self.data,
price=self.data.close[0],
size=1,
exectype=bt.Order.Market,
)
self.pos = -1
self.short_trailing_stop_price = self.high[0]
self.sl_shor_price = self.data.open[0]
# print('datetime+sig: ',dt,' sig: ',self.signal[0],'保存空头价格: ',self.short_trailing_stop_price)
if __name__ == "__main__":
# 创建Cerebro实例
cerebro = bt.Cerebro()
# 数据
csv_file = csv_file_path
png_filepath = png_file_path
# 从CSV文件加载数据
data = GenericCSV_SIG(
dataname=csv_file,
fromdate=start_date, # datetime(2023, 1, 1),
todate=end_date, # datetime(2023, 12, 29),
timeframe=bt.TimeFrame.Minutes,
nullvalue=0.0,
dtformat="%Y-%m-%d %H:%M:%S",
datetime=0,
high=3,
low=4,
open=2,
close=1,
volume=5,
openinterest=None,
sig=6,
delta=8,
)
# 添加数据到Cerebro实例
cerebro.adddata(data)
# 添加策略到Cerebro实例
cerebro.addstrategy(MyStrategy_固定止损_跟踪止盈)
# 添加观察者和分析器到Cerebro实例
# cerebro.addobserver(bt.observers.BuySell)
cerebro.addobserver(bt.observers.Value)
cerebro.addanalyzer(bt.analyzers.Returns, _name="returns")
cerebro.addanalyzer(bt.analyzers.DrawDown, _name="drawdown")
cerebro.addanalyzer(bt.analyzers.TradeAnalyzer, _name="trades")
# cerebro.addanalyzer(bt.analyzers.sharpe, __name_= "sharpe")
初始资金 = 回测资金
cerebro.broker.setcash(初始资金) # 设置初始资金
# 手续费,单手保证金,合约倍数
cerebro.broker.setcommission(
commission=单手手续费, margin=单手保证金, mult=交易乘率
) # 回测参数
# 运行回测
result = cerebro.run()
# 获取策略分析器中的结果
analyzer = result[0].analyzers
total_trades = analyzer.trades.get_analysis()["total"]["total"]
winning_trades = analyzer.trades.get_analysis()["won"]["total"]
# 获取TradeAnalyzer分析器的结果
trade_analyzer_result = analyzer.trades.get_analysis()
# 获取总收益额
total_profit = trade_analyzer_result.pnl.net.total
if total_trades > 0:
win_rate = winning_trades / total_trades
else:
win_rate = 0.0
# 打印回测报告
print("回测报告:")
print("期初权益", 初始资金)
print("期末权益", 初始资金 + round(total_profit))
print("盈亏额", round(total_profit))
print("最大回撤率,", round(analyzer.drawdown.get_analysis()["drawdown"], 2), "%")
print("胜率,", round(win_rate * 100, 2), "%")
print("交易次数,", total_trades)
print("盈利次数,", winning_trades)
print("亏损次数,", total_trades - winning_trades)
print("总手续费+滑点,", 手续费汇总)
手续费汇总 = 0
# 保存回测图像文件
plot = cerebro.plot()[0][0]
plot_filename = os.path.splitext(os.path.basename(csv_file))[0] + "ss" + "_plot.png"
# plot_path = os.path.join('部分回测报告', plot_filename)
if not os.path.exists(png_filepath):
# os.mkdir(png_filepath)
os.makedirs(png_filepath)
plot_path = os.path.join(png_filepath, plot_filename)
plot.savefig(plot_path)

View File

@@ -0,0 +1,406 @@
'''
以下是代码的详细说明:
#公众号松鼠Quant
#主页www.quant789.com
#本策略仅作学习交流使用,实盘交易盈亏投资者个人负责!!!
#版权归松鼠Quant所有禁止转发、转卖源码违者必究。
1.
导入必要的模块和库:
backtrader 用于回测功能
datetime 用于处理日期和时间
GenericCSVData 用于从CSV文件加载数据
numpy 用于数值操作
time 用于时间相关操作
matplotlib.pyplot 用于绘图
2. 定义自定义手续费模板MyCommission
继承自bt.CommInfoBase
3.
定义自定义数据源类 GenericCSV_SIG
继承自 GenericCSVData并添加了两个额外的行'sig''delta'
定义了参数 'sig''delta'
4.
定义 MyStrategy_固定止损_跟踪止盈 类:
继承自 bt.Strategybacktrader的基础策略类
定义了两个参数trailing_stop_percent 和 fixed_stop_loss_percent
初始化策略并设置各种变量和指标
实现了 next 方法该方法在数据源的每个新的K线出现时被调用
根据当前K线数据更新跟踪止盈价格
实现了跟踪止盈出场和固定止损出场
根据信号处理多头和空头仓位
在策略执行过程中打印调试信息
5.
if __name__ == "__main__": 代码块:
使用 Cerebro 实例设置回测环境
使用 GenericCSV_SIG 数据源从CSV文件加载数据
将数据源和策略添加到 Cerebro 实例中
添加观察者和分析器以评估性能
设置初始资金和经纪人参数
运行回测并获取结果
打印回测报告,包括收益率、回撤、胜率和交易统计数据
使用 matplotlib 绘制回测结果
#公众号松鼠Quant
#主页www.quant789.com
#本策略仅作学习交流使用,实盘交易盈亏投资者个人负责!!!
#版权归松鼠Quant所有禁止转发、转卖源码违者必究。
'''
import backtrader as bt
from datetime import datetime
from datetime import time as s_time
from backtrader.feeds import GenericCSVData
import numpy as np
import pandas as pd
import time
import matplotlib.pyplot as plt
import os
import itertools
from scipy.optimize import brute
手续费汇总=0
class GenericCSV_SIG(GenericCSVData):
# 从基类继承,添加一个 'sig'delta
lines = ('sig','delta')
# 添加参数为从基类继承的参数
params = (('sig',6),('delta', 8))
class MyStrategy_固定止损_跟踪止盈(bt.Strategy):
params = (
('trailing_stop_percent', 0.02), # 跟踪止盈百分比
('fixed_stop_loss_percent', 0.01), # 固定止损百分比
('duiji', 1), # 堆积
('cout_delta', 1), # 日累计delta
('delta', 1), # delta单bar
)
def __init__(self):
self.Lots=1 #下单手数
self.signal = self.datas[0].sig # 使用sig字段作为策略的信号字段
self.delta= self.datas[0].delta
# 获取数据序列别名列表
line_aliases = self.datas[0].getlinealiases()
self.pos=0
print(line_aliases)
self.high=self.datas[0].high
self.low=self.datas[0].low
self.closes=self.datas[0].close
self.open=self.datas[0].open
self.trailing_stop_percent = self.params.trailing_stop_percent
self.short_trailing_stop_price = 0
self.long_trailing_stop_price = 0
self.fixed_stop_loss_percent = self.params.fixed_stop_loss_percent
self.sl_long_price=0
self.sl_shor_price=0
self.out_long=0
self.out_short=0
self.rinei_ma=[]
self.rinei_mean=0
self.datetime_list= []
self.high_list = []
self.low_list = []
self.close_list = []
self.opens_list = []
self.deltas_list = []
self.delta_cumsum=[]
self.barN = 0
self.df = pd.DataFrame(columns=['datetime', 'high', 'low', 'close', 'open', 'delta', 'delta_cumsum'])
self.trader_df=pd.DataFrame(columns=['open', 'high', 'low', 'close', 'volume', 'openInterest','delta'])
def log(self, txt, dt=None):
'''可选,构建策略打印日志的函数:可用于打印订单记录或交易记录等'''
dt = dt or self.datas[0].datetime.date(0)
print('%s, %s' % (dt.isoformat(), txt))
# def notify_order(self, order):
# # 未被处理的订单
# if order.status in [order.Submitted, order.Accepted]:
# return
# # 已经处理的订单
# if order.status in [order.Completed, order.Canceled, order.Margin]:
# global 手续费汇总
# if order.isbuy():
# 手续费汇总 +=order.executed.comm
# self.log(
# 'BUY EXECUTED, 订单编号:%.0f,成交价格: %.2f, 手续费滑点:%.2f, 成交量: %.2f, 品种: %s,手续费汇总:%.2f' %
# (order.ref, # 订单编号
# order.executed.price, # 成交价
# order.executed.comm, # 佣金
# order.executed.size, # 成交量
# order.data._name,# 品种名称
# 手续费汇总))
# else: # Sell
# 手续费汇总 +=order.executed.comm
# self.log('SELL EXECUTED, 订单编号:%.0f,成交价格: %.2f, 手续费滑点:%.2f, 成交量: %.2f, 品种: %s,手续费汇总:%.2f' %
# (order.ref,
# order.executed.price,
# order.executed.comm,
# order.executed.size,
# order.data._name,
# 手续费汇总))
def next(self):
#公众号松鼠Quant
#主页www.quant789.com
#本策略仅作学习交流使用,实盘交易盈亏投资者个人负责!!!
#版权归松鼠Quant所有禁止转发、转卖源码违者必究。
#bar线计数初始化
self.barN += 1
position = self.getposition(self.datas[0]).size
#时间轴
dt = bt.num2date(self.data.datetime[0])
#更新跟踪止损价格
def 每日重置数据():
# 获取当前时间
current_time = dt.time()
#print(current_time)
# 设置清仓操作的时间范围114:55到15:00
clearing_time1_start = s_time(14, 55)
clearing_time1_end = s_time(15, 0)
# 设置清仓操作的时间范围200:55到01:00
clearing_time2_start = s_time(2, 25)
clearing_time2_end = s_time(2, 30)
# 创建一个标志变量
clearing_executed = False
if clearing_time1_start <= current_time <= clearing_time1_end and not clearing_executed :
clearing_executed = True # 设置标志变量为已执行
self.rinei_ma=[]
self.delta_cumsum=[]
self.deltas_list=[]
elif clearing_time2_start <= current_time <= clearing_time2_end and not clearing_executed :
clearing_executed = True # 设置标志变量为已执行
self.rinei_ma=[]
self.delta_cumsum=[]
self.deltas_list=[]
# 如果不在任何时间范围内,可以执行其他操作
else:
self.rinei_ma.append(self.closes[0])
self.rinei_mean = np.mean(self.rinei_ma)
#self.delta_cumsum=[]
#self.deltas_list=[]
#print('rinei_ma',self.rinei_ma)
clearing_executed = False
pass
return clearing_executed
run_kg=每日重置数据()
#过滤成交量为0或小于0
if self.data.volume[0] <= 0 :
return
#print(f'volume,{self.data.volume[0]}')
if self.long_trailing_stop_price >0 and self.pos>0:
#print('datetime+sig: ',dt,'旧多头出线',self.long_trailing_stop_price,'low',self.low[0])
self.long_trailing_stop_price = self.low[0] if self.long_trailing_stop_price<self.low[0] else self.long_trailing_stop_price
#print('datetime+sig: ',dt,'多头出线',self.long_trailing_stop_price)
if self.short_trailing_stop_price >0 and self.pos<0:
#print('datetime+sig: ',dt,'旧空头出线',self.short_trailing_stop_price,'high',self.high[0])
self.short_trailing_stop_price = self.high[0] if self.high[0] <self.short_trailing_stop_price else self.short_trailing_stop_price
#print('datetime+sig: ',dt,'空头出线',self.short_trailing_stop_price)
self.out_long=self.long_trailing_stop_price * (1 - self.trailing_stop_percent)
self.out_short=self.short_trailing_stop_price*(1 + self.trailing_stop_percent)
#print('datetime+sig: ',dt,'空头出线',self.out_short)
#print('datetime+sig: ',dt,'多头出线',self.out_long)
# 跟踪出场
if self.out_long >0:
if self.low[0] < self.out_long and self.pos>0 and self.sl_long_price>0 and self.low[0]>self.sl_long_price:
#print('--多头止盈出场datetime+sig: ',dt,'Trailing stop triggered: Closing position','TR',self.out_long,'low', self.low[0])
self.close(data=self.data, price=self.data.close[0],size=self.Lots, exectype=bt.Order.Market)
self.long_trailing_stop_price = 0
self.sl_long_price=0
self.out_long=0
self.pos = 0
if self.out_short>0:
if self.high[0] > self.out_short and self.pos<0 and self.sl_shor_price>0 and self.high[0]<self.sl_shor_price:
#print('--空头止盈出场datetime+sig: ',dt,'Trailing stop triggered: Closing position: ','TR',self.out_short,'high', self.high[0])
self.close(data=self.data, price=self.data.close[0],size=self.Lots, exectype=bt.Order.Market)
self.short_trailing_stop_price = 0
self.sl_shor_price=0
self.out_shor=0
self.pos = 0
# 固定止损
self.fixed_stop_loss_L = self.sl_long_price * (1 - self.fixed_stop_loss_percent)
if self.sl_long_price>0 and self.fixed_stop_loss_L>0 and self.pos > 0 and self.closes[0] < self.fixed_stop_loss_L:
#print('--多头止损datetime+sig: ', dt, 'Fixed stop loss triggered: Closing position', 'SL', self.fixed_stop_loss_L, 'close', self.closes[0])
self.close(data=self.data, price=self.data.close[0],size=self.Lots, exectype=bt.Order.Market)
self.long_trailing_stop_price = 0
self.sl_long_price=0
self.out_long = 0
self.pos = 0
self.fixed_stop_loss_S = self.sl_shor_price * (1 + self.fixed_stop_loss_percent)
if self.sl_shor_price>0 and self.fixed_stop_loss_S>0 and self.pos < 0 and self.closes[0] > self.fixed_stop_loss_S:
#print('--空头止损datetime+sig: ', dt, 'Fixed stop loss triggered: Closing position', 'SL', self.fixed_stop_loss_S, 'close', self.closes[0])
self.close(data=self.data, price=self.data.close[0], size=self.Lots,exectype=bt.Order.Market)
self.short_trailing_stop_price = 0
self.sl_shor_price=0
self.out_short = 0
self.pos = 0
# 更新最高价和最低价的列表
self.datetime_list.append(dt)
self.high_list.append(self.data.high[0])
self.low_list.append(self.data.low[0])
self.close_list.append(self.data.close[0])
self.opens_list.append(self.data.open[0])
self.deltas_list.append(self.data.delta[0])
# 计算delta累计
self.delta_cumsum.append(sum(self.deltas_list))
# 将当前行数据添加到 DataFrame
# new_row = {
# 'datetime': dt,
# 'high': self.data.high[0],
# 'low': self.data.low[0],
# 'close': self.data.close[0],
# 'open': self.data.open[0],
# 'delta': self.data.delta[0],
# 'delta_cumsum': sum(self.deltas_list)
# }
# # 使用pandas.concat代替append
# self.df = pd.concat([self.df, pd.DataFrame([new_row])], ignore_index=True)
# # 检查文件是否存在
# csv_file_path = f"output.csv"
# if os.path.exists(csv_file_path):
# # 仅保存最后一行数据
# self.df.tail(1).to_csv(csv_file_path, mode='a', header=False, index=False)
# else:
# # 创建新文件并保存整个DataFrame
# self.df.to_csv(csv_file_path, index=False)
#
if run_kg==False : #
#print(self.delta_cumsum)
开多组合= self.rinei_mean>0 and self.closes[0]>self.rinei_mean and self.signal[0] >self.params.duiji and self.data.delta[0]>self.params.delta and self.delta_cumsum[-1]>self.params.cout_delta
开空组合= self.rinei_mean>0 and self.closes[0]<self.rinei_mean and self.signal[0] <-self.params.duiji and self.data.delta[0]<-self.params.delta and self.delta_cumsum[-1]<-self.params.cout_delta
平多条件=self.pos<0 and self.signal[0] >self.params.duiji
平空条件=self.pos>0 and self.signal[0] <-self.params.duiji
if self.pos !=1 : #
if 平多条件:
#print('datetime+sig: ', dt, 'Fixed stop loss triggered: Closing position', 'SL', self.fixed_stop_loss_S, 'close', self.closes[0])
self.close(data=self.data, price=self.data.close[0], exectype=bt.Order.Market)
self.short_trailing_stop_price = 0
self.sl_shor_price=0
self.out_short = 0
self.pos = 0
if 开多组合 : #
self.buy(data=self.data, price=self.data.close[0], size=1, exectype=bt.Order.Market)
self.pos=1
self.long_trailing_stop_price=self.low[0]
self.sl_long_price=self.data.open[0]
#print('datetime+sig: ',dt,' sig: ',self.signal[0],'保存多头价格: ',self.long_trailing_stop_price)
if self.pos !=-1 : #
if 平空条件:
#print('datetime+sig: ', dt, 'Fixed stop loss triggered: Closing position', 'SL', self.fixed_stop_loss_L, 'close', self.closes[0])
self.close(data=self.data, price=self.data.close[0], exectype=bt.Order.Market)
self.long_trailing_stop_price = 0
self.sl_long_price=0
self.out_long = 0
self.pos = 0
if 开空组合: #
self.sell(data=self.data, price=self.data.close[0], size=1, exectype=bt.Order.Market)
self.pos=-1
self.short_trailing_stop_price=self.high[0]
self.sl_shor_price=self.data.open[0]
#print('datetime+sig: ',dt,' sig: ',self.signal[0],'保存空头价格: ',self.short_trailing_stop_price)
if __name__ == "__main__":
#公众号松鼠Quant
#主页www.quant789.com
#本策略仅作学习交流使用,实盘交易盈亏投资者个人负责!!!
#版权归松鼠Quant所有禁止转发、转卖源码违者必究。
# 创建Cerebro实例
cerebro = bt.Cerebro()
#数据
csv_file='E:/of_data/tick生成的OF数据/data_rs_merged/上期所/ag888/ag888_rs_2023_5M_back_ofdata_dj.csv' #
# 从CSV文件加载数据
data = GenericCSV_SIG(
dataname=csv_file,
fromdate=datetime(2023,1,1),
todate=datetime(2023,12,29),
timeframe=bt.TimeFrame.Minutes,
nullvalue=0.0,
dtformat='%Y-%m-%d %H:%M:%S',
datetime=0,
high=3,
low=4,
open=2,
close=1,
volume=5,
openinterest=None,
sig=6,
delta=8
)
# 评估函数,输入参数,返回评估函数值,这里是总市值,要求最大化
def evaluate_strategy(trailing_stop_percent, fixed_stop_loss_percent,duiji,cout_delta,delta):
cerebro = bt.Cerebro()
cerebro.addstrategy(MyStrategy_固定止损_跟踪止盈)
cerebro.adddata(data) # 确保你有一个有效的数据源
cerebro.broker.setcash(10000.0)
#手续费,单手保证金,合约倍数
cerebro.broker.setcommission(commission=14, margin=5000.0,mult=10)#回测参数
cerebro.run()
return cerebro.broker.getvalue()
# 创建参数网格
trailing_stop_percents = np.arange(0.005, 0.025, 0.005)
fixed_stop_loss_percents = np.arange(0.01, 0.050, 0.01)
duiji= np.arange(1, 3, 1) #
cout_delta= np.arange(500, 3500, 500)
delta=np.arange(500, 3500, 500)
# 生成所有参数组合
combinations = list(itertools.product(trailing_stop_percents, fixed_stop_loss_percents,duiji,cout_delta,delta))
# 评估所有参数组合并找到最佳参数
best_value = 0
best_parameters = None
for combo in combinations:
value = evaluate_strategy(*combo)
if value > best_value:
best_value = value
best_parameters = combo
print(f'combo: {combo},best_value: {best_value},best_parameters: {best_parameters}')
# 打印最佳参数组合
print(f"最佳参数组合: 跟踪止损百分比 {best_parameters[0]}%, 固定止损百分比 {best_parameters[1]}%")
print(f"最大市值: {best_value}")
#公众号松鼠Quant
#主页www.quant789.com
#本策略仅作学习交流使用,实盘交易盈亏投资者个人负责!!!

View File

@@ -0,0 +1,218 @@
import backtrader as bt
from datetime import datetime
from datetime import time as s_time
from backtrader.feeds import GenericCSVData
import numpy as np
import pandas as pd
import itertools
class GenericCSV_SIG(GenericCSVData):
lines = ('sig', 'delta')
params = (('sig', 6), ('delta', 8))
class MyStrategy_固定止损_跟踪止盈(bt.Strategy):
params = (
('trailing_stop_percent', 0.02),
('fixed_stop_loss_percent', 0.01),
('duiji', 1),
('cout_delta', 1),
('delta', 1),
)
def __init__(self):
self.Lots = 1
self.signal = self.datas[0].sig
self.delta = self.datas[0].delta
self.pos = 0
self.high = self.datas[0].high
self.low = self.datas[0].low
self.closes = self.datas[0].close
self.open = self.datas[0].open
self.trailing_stop_percent = self.params.trailing_stop_percent
self.short_trailing_stop_price = 0
self.long_trailing_stop_price = 0
self.fixed_stop_loss_percent = self.params.fixed_stop_loss_percent
self.sl_long_price = 0
self.sl_shor_price = 0
self.out_long = 0
self.out_short = 0
self.rinei_ma = []
self.rinei_mean = 0
self.datetime_list = []
self.high_list = []
self.low_list = []
self.close_list = []
self.opens_list = []
self.deltas_list = []
self.delta_cumsum = []
self.barN = 0
def log(self, txt, dt=None):
dt = dt or self.datas[0].datetime.date(0)
print('%s, %s' % (dt.isoformat(), txt))
def next(self):
self.barN += 1
position = self.getposition(self.datas[0]).size
dt = bt.num2date(self.data.datetime[0])
def 每日重置数据():
current_time = dt.time()
clearing_time1_start = s_time(14, 55)
clearing_time1_end = s_time(15, 0)
clearing_time2_start = s_time(2, 25)
clearing_time2_end = s_time(2, 30)
clearing_executed = False
if clearing_time1_start <= current_time <= clearing_time1_end and not clearing_executed:
clearing_executed = True
self.rinei_ma = []
self.delta_cumsum = []
self.deltas_list = []
elif clearing_time2_start <= current_time <= clearing_time2_end and not clearing_executed:
clearing_executed = True
self.rinei_ma = []
self.delta_cumsum = []
self.deltas_list = []
else:
self.rinei_ma.append(self.closes[0])
self.rinei_mean = np.mean(self.rinei_ma)
clearing_executed = False
return clearing_executed
run_kg = 每日重置数据()
if self.data.volume[0] <= 0:
return
if self.long_trailing_stop_price > 0 and self.pos > 0:
self.long_trailing_stop_price = max(self.low[0], self.long_trailing_stop_price)
if self.short_trailing_stop_price > 0 and self.pos < 0:
self.short_trailing_stop_price = min(self.high[0], self.short_trailing_stop_price)
self.out_long = self.long_trailing_stop_price * (1 - self.trailing_stop_percent)
self.out_short = self.short_trailing_stop_price * (1 + self.trailing_stop_percent)
if self.out_long > 0 and self.low[0] < self.out_long and self.pos > 0 and self.sl_long_price > 0 and self.low[0] > self.sl_long_price:
self.close(data=self.data, price=self.data.close[0], size=self.Lots, exectype=bt.Order.Market)
self.long_trailing_stop_price = 0
self.sl_long_price = 0
self.out_long = 0
self.pos = 0
if self.out_short > 0 and self.high[0] > self.out_short and self.pos < 0 and self.sl_shor_price > 0 and self.high[0] < self.sl_shor_price:
self.close(data=self.data, price=self.data.close[0], size=self.Lots, exectype=bt.Order.Market)
self.short_trailing_stop_price = 0
self.sl_shor_price = 0
self.out_short = 0
self.pos = 0
self.fixed_stop_loss_L = self.sl_long_price * (1 - self.fixed_stop_loss_percent)
if self.sl_long_price > 0 and self.fixed_stop_loss_L > 0 and self.pos > 0 and self.closes[0] < self.fixed_stop_loss_L:
self.close(data=self.data, price=self.data.close[0], size=self.Lots, exectype=bt.Order.Market)
self.long_trailing_stop_price = 0
self.sl_long_price = 0
self.out_long = 0
self.pos = 0
self.fixed_stop_loss_S = self.sl_shor_price * (1 + self.fixed_stop_loss_percent)
if self.sl_shor_price > 0 and self.fixed_stop_loss_S > 0 and self.pos < 0 and self.closes[0] > self.fixed_stop_loss_S:
self.close(data=self.data, price=self.data.close[0], size=self.Lots, exectype=bt.Order.Market)
self.short_trailing_stop_price = 0
self.sl_shor_price = 0
self.out_short = 0
self.pos = 0
self.datetime_list.append(dt)
self.high_list.append(self.data.high[0])
self.low_list.append(self.data.low[0])
self.close_list.append(self.data.close[0])
self.opens_list.append(self.data.open[0])
self.deltas_list.append(self.data.delta[0])
self.delta_cumsum.append(sum(self.deltas_list))
if run_kg == False:
开多组合 = self.rinei_mean > 0 and self.closes[0] > self.rinei_mean and self.signal[0] > self.params.duiji and self.data.delta[0] > self.params.delta and self.delta_cumsum[-1] > self.params.cout_delta
开空组合 = self.rinei_mean > 0 and self.closes[0] < self.rinei_mean and self.signal[0] < -self.params.duiji and self.data.delta[0] < -self.params.delta and self.delta_cumsum[-1] < -self.params.cout_delta
平多条件 = self.pos < 0 and self.signal[0] > self.params.duiji
平空条件 = self.pos > 0 and self.signal[0] < -self.params.duiji
if self.pos != 1:
if 平多条件:
self.close(data=self.data, price=self.data.close[0], exectype=bt.Order.Market)
self.short_trailing_stop_price = 0
self.sl_shor_price = 0
self.out_short = 0
self.pos = 0
if 开多组合:
self.buy(data=self.data, price=self.data.close[0], size=1, exectype=bt.Order.Market)
self.pos = 1
self.long_trailing_stop_price = self.low[0]
self.sl_long_price = self.data.open[0]
if self.pos != -1:
if 平空条件:
self.close(data=self.data, price=self.data.close[0], exectype=bt.Order.Market)
self.long_trailing_stop_price = 0
self.sl_long_price = 0
self.out_long = 0
self.pos = 0
if 开空组合:
self.sell(data=self.data, price=self.data.close[0], size=1, exectype=bt.Order.Market)
self.pos = -1
self.short_trailing_stop_price = self.high[0]
self.sl_shor_price = self.data.open[0]
if __name__ == "__main__":
def evaluate_strategy(trailing_stop_percent, fixed_stop_loss_percent, duiji, cout_delta, delta):
cerebro = bt.Cerebro()
cerebro.addstrategy(MyStrategy_固定止损_跟踪止盈,
trailing_stop_percent=trailing_stop_percent,
fixed_stop_loss_percent=fixed_stop_loss_percent,
duiji=duiji,
cout_delta=cout_delta,
delta=delta)
data = GenericCSV_SIG(
dataname=csv_file,
fromdate=datetime(2023, 1, 1),
todate=datetime(2023, 12, 29),
timeframe=bt.TimeFrame.Minutes,
nullvalue=0.0,
dtformat='%Y-%m-%d %H:%M:%S',
datetime=0,
high=3,
low=4,
open=2,
close=1,
volume=5,
openinterest=None,
sig=6,
delta=8
)
cerebro.adddata(data)
cerebro.broker.setcash(10000.0)
cerebro.broker.setcommission(commission=14, margin=5000.0, mult=10)
cerebro.run()
return cerebro.broker.getvalue()
csv_file = 'E:/of_data/tick生成的OF数据/data_rs_merged/上期所/ag888/ag888_rs_2023_5M_back_ofdata_dj.csv'
trailing_stop_percents = np.arange(0.005, 0.025, 0.005)
fixed_stop_loss_percents = np.arange(0.01, 0.050, 0.01)
duiji = np.arange(1, 3, 1)
cout_delta = np.arange(500, 3500, 500)
delta = np.arange(500, 3500, 500)
combinations = list(itertools.product(trailing_stop_percents, fixed_stop_loss_percents, duiji, cout_delta, delta))
best_value = 0
best_parameters = None
for combo in combinations:
value = evaluate_strategy(*combo)
if value > best_value:
best_value = value
best_parameters = combo
print(f'combo: {combo}, best_value: {best_value}, best_parameters: {best_parameters}')
print(f"最佳参数组合: 跟踪止损百分比 {best_parameters[0]}%, 固定止损百分比 {best_parameters[1]}%")
print(f"最大市值: {best_value}")

View File

@@ -0,0 +1,302 @@
import backtrader as bt
from datetime import datetime, time as s_time
from backtrader.feeds import GenericCSVData
import numpy as np
from deap import base, creator, tools, algorithms
import random
# 自定义CSV数据类
class GenericCSV_SIG(GenericCSVData):
lines = ("sig", "delta")
params = (("sig", 6), ("delta", 8))
# 自定义策略类
class MyStrategy_固定止损_跟踪止盈(bt.Strategy):
params = (
("trailing_stop_percent", 0.01),
("fixed_stop_loss_percent", 0.005),
("duiji", 1),
("cout_delta", 1),
("delta", 1),
)
def __init__(self):
# 初始化变量
self.Lots = 1
self.signal = self.datas[0].sig
self.delta = self.datas[0].delta
self.pos = 0
self.high = self.datas[0].high
self.low = self.datas[0].low
self.closes = self.datas[0].close
self.open = self.datas[0].open
self.trailing_stop_percent = self.params.trailing_stop_percent
self.short_trailing_stop_price = 0
self.long_trailing_stop_price = 0
self.fixed_stop_loss_percent = self.params.fixed_stop_loss_percent
self.sl_long_price = 0
self.sl_shor_price = 0
self.out_long = 0
self.out_short = 0
self.rinei_ma = []
self.rinei_mean = 0
self.datetime_list = []
self.high_list = []
self.low_list = []
self.close_list = []
self.opens_list = []
self.deltas_list = []
self.delta_cumsum = []
self.barN = 0
def log(self, txt, dt=None):
dt = dt or self.datas[0].datetime.date(0)
print("%s, %s" % (dt.isoformat(), txt))
def next(self):
self.barN += 1
# position = self.getposition(self.datas[0]).size
dt = bt.num2date(self.data.datetime[0])
def reset_daily_data():
current_time = dt.time()
clearing_time1_start = s_time(14, 55)
clearing_time1_end = s_time(15, 0)
clearing_time2_start = s_time(22, 55)
clearing_time2_end = s_time(23, 0)
clearing_executed = False
if clearing_time1_start <= current_time <= clearing_time1_end and not clearing_executed:
clearing_executed = True
self.rinei_ma = []
self.delta_cumsum = []
self.deltas_list = []
elif clearing_time2_start <= current_time <= clearing_time2_end and not clearing_executed:
clearing_executed = True
self.rinei_ma = []
self.delta_cumsum = []
self.deltas_list = []
else:
self.rinei_ma.append(self.closes[0])
self.rinei_mean = np.mean(self.rinei_ma)
clearing_executed = False
return clearing_executed
run_kg = reset_daily_data()
if self.data.volume[0] <= 0:
return
if self.long_trailing_stop_price > 0 and self.pos > 0:
self.long_trailing_stop_price = max(self.low[0], self.long_trailing_stop_price)
if self.short_trailing_stop_price > 0 and self.pos < 0:
self.short_trailing_stop_price = min(self.high[0], self.short_trailing_stop_price)
self.out_long = self.long_trailing_stop_price * (1 - self.trailing_stop_percent)
self.out_short = self.short_trailing_stop_price * (1 + self.trailing_stop_percent)
if (
self.out_long > 0
and self.low[0] < self.out_long
and self.pos > 0
and self.sl_long_price > 0
and self.low[0] > self.sl_long_price
):
self.close(data=self.data, price=self.data.close[0], size=self.Lots, exectype=bt.Order.Market)
self.long_trailing_stop_price = 0
self.sl_long_price = 0
self.out_long = 0
self.pos = 0
if (
self.out_short > 0
and self.high[0] > self.out_short
and self.pos < 0
and self.sl_shor_price > 0
and self.high[0] < self.sl_shor_price
):
self.close(data=self.data, price=self.data.close[0], size=self.Lots, exectype=bt.Order.Market)
self.short_trailing_stop_price = 0
self.sl_shor_price = 0
self.out_short = 0
self.pos = 0
self.fixed_stop_loss_L = self.sl_long_price * (1 - self.fixed_stop_loss_percent)
if (
self.sl_long_price > 0
and self.fixed_stop_loss_L > 0
and self.pos > 0
and self.closes[0] < self.fixed_stop_loss_L
):
self.close(data=self.data, price=self.data.close[0], size=self.Lots, exectype=bt.Order.Market)
self.long_trailing_stop_price = 0
self.sl_long_price = 0
self.out_long = 0
self.pos = 0
self.fixed_stop_loss_S = self.sl_shor_price * (1 + self.fixed_stop_loss_percent)
if (
self.sl_shor_price > 0
and self.fixed_stop_loss_S > 0
and self.pos < 0
and self.closes[0] > self.fixed_stop_loss_S
):
self.close(data=self.data, price=self.data.close[0], size=self.Lots, exectype=bt.Order.Market)
self.short_trailing_stop_price = 0
self.sl_shor_price = 0
self.out_short = 0
self.pos = 0
self.datetime_list.append(dt)
self.high_list.append(self.data.high[0])
self.low_list.append(self.data.low[0])
self.close_list.append(self.data.close[0])
self.opens_list.append(self.data.open[0])
self.deltas_list.append(self.data.delta[0])
self.delta_cumsum.append(sum(self.deltas_list))
if not run_kg:
开多组合 = (
self.rinei_mean > 0
and self.closes[0] > self.rinei_mean
and self.signal[0] > self.params.duiji
and self.data.delta[0] > self.params.delta
and self.delta_cumsum[-1] > self.params.cout_delta
)
开空组合 = (
self.rinei_mean > 0
and self.closes[0] < self.rinei_mean
and self.signal[0] < -self.params.duiji
and self.data.delta[0] < -self.params.delta
and self.delta_cumsum[-1] < -self.params.cout_delta
)
平多条件 = self.pos < 0 and self.signal[0] > self.params.duiji
平空条件 = self.pos > 0 and self.signal[0] < -self.params.duiji
if self.pos != 1:
if 平多条件:
self.close(data=self.data, price=self.data.close[0], exectype=bt.Order.Market)
self.short_trailing_stop_price = 0
self.sl_shor_price = 0
self.out_short = 0
self.pos = 0
if 开多组合:
self.buy(data=self.data, price=self.data.close[0], size=1, exectype=bt.Order.Market)
self.pos = 1
self.long_trailing_stop_price = self.low[0]
self.sl_long_price = self.data.open[0]
if self.pos != -1:
if 平空条件:
self.close(data=self.data, price=self.data.close[0], exectype=bt.Order.Market)
self.long_trailing_stop_price = 0
self.sl_long_price = 0
self.out_long = 0
self.pos = 0
if 开空组合:
self.sell(data=self.data, price=self.data.close[0], size=1, exectype=bt.Order.Market)
self.pos = -1
self.short_trailing_stop_price = self.high[0]
self.sl_shor_price = self.data.open[0]
# 评估策略函数
def evaluate_strategy(trailing_stop_percent, fixed_stop_loss_percent, duiji, cout_delta, delta, csv_file):
cerebro = bt.Cerebro()
cerebro.addstrategy(
MyStrategy_固定止损_跟踪止盈,
trailing_stop_percent=trailing_stop_percent,
fixed_stop_loss_percent=fixed_stop_loss_percent,
duiji=duiji,
cout_delta=cout_delta,
delta=delta,
)
data = GenericCSV_SIG(
dataname=csv_file,
fromdate=datetime(2023, 1, 1),
todate=datetime(2023, 12, 29),
timeframe=bt.TimeFrame.Minutes,
nullvalue=0.0,
dtformat="%Y-%m-%d %H:%M:%S",
datetime=0,
high=3,
low=4,
open=2,
close=1,
volume=5,
openinterest=None,
sig=6,
delta=8,
)
cerebro.adddata(data)
cerebro.broker.setcash(500000.0)
cerebro.broker.setcommission(commission=14, margin=150000.0, mult=300)
cerebro.run()
return cerebro.broker.getvalue()
# 遗传算法优化部分
def optimize_with_ga(csv_file):
# 创建适应度和个体
creator.create("FitnessMax", base.Fitness, weights=(1.0,))
creator.create("Individual", list, fitness=creator.FitnessMax)
# 定义个体生成和变异操作
toolbox = base.Toolbox()
toolbox.register("attr_trailing_stop_percent", random.uniform, 0.002, 0.01)
toolbox.register("attr_fixed_stop_loss_percent", random.uniform, 0.002, 0.01)
toolbox.register("attr_duiji", random.randint, 3, 5)
toolbox.register("attr_cout_delta", random.randint, 20, 400)
toolbox.register("attr_delta", random.randint, 20, 400)
toolbox.register(
"individual",
tools.initCycle,
creator.Individual,
(
toolbox.attr_trailing_stop_percent,
toolbox.attr_fixed_stop_loss_percent,
toolbox.attr_duiji,
toolbox.attr_cout_delta,
toolbox.attr_delta,
),
)
toolbox.register("population", tools.initRepeat, list, toolbox.individual)
# 定义评价函数
def evaluate(individual):
trailing_stop_percent, fixed_stop_loss_percent, duiji, cout_delta, delta = individual
result = evaluate_strategy(trailing_stop_percent, fixed_stop_loss_percent, duiji, cout_delta, delta, csv_file)
if isinstance(result, complex):
print(f"Complex result encountered: {result}")
return (result,)
toolbox.register("evaluate", evaluate)
toolbox.register("mate", tools.cxBlend, alpha=0.5)
toolbox.register(
"mutate",
tools.mutPolynomialBounded,
low=[0.002, 0.002, 3, 20, 20],
up=[0.01, 0.01, 5, 400, 400],
eta=0.1,
indpb=0.2,
)
toolbox.register("select", tools.selTournament, tournsize=3)
# 遗传算法主循环
population = toolbox.population(n=50)
ngen, cxpb, mutpb = 40, 0.5, 0.2
algorithms.eaSimple(population, toolbox, cxpb, mutpb, ngen, verbose=True)
# 获取最佳个体
best_individual = tools.selBest(population, 1)[0]
return best_individual
if __name__ == "__main__":
csv_file = r"D:\BaiduNetdiskDownload\主力连续\tick生成的OF数据(5M)\data_rs_merged\中金所\IM888\IM888_rs_2023_5T_back_ofdata_dj.csv"
best_parameters = optimize_with_ga(csv_file)
print(f"最佳参数组合: 跟踪止损百分比 {best_parameters[0]}%, 固定止损百分比 {best_parameters[1]}%")
print(f"对冲 {best_parameters[2]}, 策略 {best_parameters[3]}, 增量 {best_parameters[4]}")

View File

@@ -0,0 +1,270 @@
import backtrader as bt
from datetime import datetime
from datetime import time as s_time
from backtrader.feeds import GenericCSVData
import numpy as np
import pandas as pd
import itertools
import multiprocessing
class GenericCSV_SIG(GenericCSVData):
lines = ("sig", "delta")
params = (("sig", 6), ("delta", 8))
class MyStrategy_固定止损_跟踪止盈(bt.Strategy):
params = (
("trailing_stop_percent", 0.02),
("fixed_stop_loss_percent", 0.01),
("duiji", 1),
("cout_delta", 1),
("delta", 1),
)
def __init__(self):
self.Lots = 1
self.signal = self.datas[0].sig
self.delta = self.datas[0].delta
self.pos = 0
self.high = self.datas[0].high
self.low = self.datas[0].low
self.closes = self.datas[0].close
self.open = self.datas[0].open
self.trailing_stop_percent = self.params.trailing_stop_percent
self.short_trailing_stop_price = 0
self.long_trailing_stop_price = 0
self.fixed_stop_loss_percent = self.params.fixed_stop_loss_percent
self.sl_long_price = 0
self.sl_shor_price = 0
self.out_long = 0
self.out_short = 0
self.rinei_ma = []
self.rinei_mean = 0
self.datetime_list = []
self.high_list = []
self.low_list = []
self.close_list = []
self.opens_list = []
self.deltas_list = []
self.delta_cumsum = []
self.barN = 0
def log(self, txt, dt=None):
dt = dt or self.datas[0].datetime.date(0)
print("%s, %s" % (dt.isoformat(), txt))
def next(self):
self.barN += 1
position = self.getposition(self.datas[0]).size
dt = bt.num2date(self.data.datetime[0])
def 每日重置数据():
current_time = dt.time()
clearing_time1_start = s_time(14, 55)
clearing_time1_end = s_time(15, 0)
clearing_time2_start = s_time(22, 55)
clearing_time2_end = s_time(23, 00)
clearing_executed = False
if clearing_time1_start <= current_time <= clearing_time1_end and not clearing_executed:
clearing_executed = True
self.rinei_ma = []
self.delta_cumsum = []
self.deltas_list = []
elif clearing_time2_start <= current_time <= clearing_time2_end and not clearing_executed:
clearing_executed = True
self.rinei_ma = []
self.delta_cumsum = []
self.deltas_list = []
else:
self.rinei_ma.append(self.closes[0])
self.rinei_mean = np.mean(self.rinei_ma)
clearing_executed = False
return clearing_executed
run_kg = 每日重置数据()
if self.data.volume[0] <= 0:
return
if self.long_trailing_stop_price > 0 and self.pos > 0:
self.long_trailing_stop_price = max(self.low[0], self.long_trailing_stop_price)
if self.short_trailing_stop_price > 0 and self.pos < 0:
self.short_trailing_stop_price = min(self.high[0], self.short_trailing_stop_price)
self.out_long = self.long_trailing_stop_price * (1 - self.trailing_stop_percent)
self.out_short = self.short_trailing_stop_price * (1 + self.trailing_stop_percent)
if (
self.out_long > 0
and self.low[0] < self.out_long
and self.pos > 0
and self.sl_long_price > 0
and self.low[0] > self.sl_long_price
):
self.close(data=self.data, price=self.data.close[0], size=self.Lots, exectype=bt.Order.Market)
self.long_trailing_stop_price = 0
self.sl_long_price = 0
self.out_long = 0
self.pos = 0
if (
self.out_short > 0
and self.high[0] > self.out_short
and self.pos < 0
and self.sl_shor_price > 0
and self.high[0] < self.sl_shor_price
):
self.close(data=self.data, price=self.data.close[0], size=self.Lots, exectype=bt.Order.Market)
self.short_trailing_stop_price = 0
self.sl_shor_price = 0
self.out_short = 0
self.pos = 0
self.fixed_stop_loss_L = self.sl_long_price * (1 - self.fixed_stop_loss_percent)
if (
self.sl_long_price > 0
and self.fixed_stop_loss_L > 0
and self.pos > 0
and self.closes[0] < self.fixed_stop_loss_L
):
self.close(data=self.data, price=self.data.close[0], size=self.Lots, exectype=bt.Order.Market)
self.long_trailing_stop_price = 0
self.sl_long_price = 0
self.out_long = 0
self.pos = 0
self.fixed_stop_loss_S = self.sl_shor_price * (1 + self.fixed_stop_loss_percent)
if (
self.sl_shor_price > 0
and self.fixed_stop_loss_S > 0
and self.pos < 0
and self.closes[0] > self.fixed_stop_loss_S
):
self.close(data=self.data, price=self.data.close[0], size=self.Lots, exectype=bt.Order.Market)
self.short_trailing_stop_price = 0
self.sl_shor_price = 0
self.out_short = 0
self.pos = 0
self.datetime_list.append(dt)
self.high_list.append(self.data.high[0])
self.low_list.append(self.data.low[0])
self.close_list.append(self.data.close[0])
self.opens_list.append(self.data.open[0])
self.deltas_list.append(self.data.delta[0])
self.delta_cumsum.append(sum(self.deltas_list))
if run_kg == False:
开多组合 = (
self.rinei_mean > 0
and self.closes[0] > self.rinei_mean
and self.signal[0] > self.params.duiji
and self.data.delta[0] > self.params.delta
and self.delta_cumsum[-1] > self.params.cout_delta
)
开空组合 = (
self.rinei_mean > 0
and self.closes[0] < self.rinei_mean
and self.signal[0] < -self.params.duiji
and self.data.delta[0] < -self.params.delta
and self.delta_cumsum[-1] < -self.params.cout_delta
)
平多条件 = self.pos < 0 and self.signal[0] > self.params.duiji
平空条件 = self.pos > 0 and self.signal[0] < -self.params.duiji
if self.pos != 1:
if 平多条件:
self.close(data=self.data, price=self.data.close[0], exectype=bt.Order.Market)
self.short_trailing_stop_price = 0
self.sl_shor_price = 0
self.out_short = 0
self.pos = 0
if 开多组合:
self.buy(data=self.data, price=self.data.close[0], size=1, exectype=bt.Order.Market)
self.pos = 1
self.long_trailing_stop_price = self.low[0]
self.sl_long_price = self.data.open[0]
if self.pos != -1:
if 平空条件:
self.close(data=self.data, price=self.data.close[0], exectype=bt.Order.Market)
self.long_trailing_stop_price = 0
self.sl_long_price = 0
self.out_long = 0
self.pos = 0
if 开空组合:
self.sell(data=self.data, price=self.data.close[0], size=1, exectype=bt.Order.Market)
self.pos = -1
self.short_trailing_stop_price = self.high[0]
self.sl_shor_price = self.data.open[0]
def evaluate_strategy(trailing_stop_percent, fixed_stop_loss_percent, duiji, cout_delta, delta, csv_file):
cerebro = bt.Cerebro()
cerebro.addstrategy(
MyStrategy_固定止损_跟踪止盈,
trailing_stop_percent=trailing_stop_percent,
fixed_stop_loss_percent=fixed_stop_loss_percent,
duiji=duiji,
cout_delta=cout_delta,
delta=delta,
)
data = GenericCSV_SIG(
dataname=csv_file,
fromdate=datetime(2023, 1, 1),
todate=datetime(2023, 12, 29),
timeframe=bt.TimeFrame.Minutes,
nullvalue=0.0,
dtformat="%Y-%m-%d %H:%M:%S",
datetime=0,
high=3,
low=4,
open=2,
close=1,
volume=5,
openinterest=None,
sig=6,
delta=8,
)
cerebro.adddata(data)
cerebro.broker.setcash(500000.0)
cerebro.broker.setcommission(commission=14, margin=150000.0, mult=300)
cerebro.run()
return cerebro.broker.getvalue(), (trailing_stop_percent, fixed_stop_loss_percent, duiji, cout_delta, delta)
def run_backtest(params):
trailing_stop_percent, fixed_stop_loss_percent, duiji, cout_delta, delta, csv_file = params
return evaluate_strategy(trailing_stop_percent, fixed_stop_loss_percent, duiji, cout_delta, delta, csv_file)
if __name__ == "__main__":
csv_file = (
r"E:\of_data\主力连续\tick生成的OF数据(1M)\data_rs_merged\中金所\IF888\IF888_rs_2023_1T_back_ofdata_dj.csv"
)
trailing_stop_percents = np.arange(0.005, 0.020, 0.005)
fixed_stop_loss_percents = np.arange(0.01, 0.040, 0.01)
duiji = np.arange(1, 3, 1)
cout_delta = np.arange(20, 220, 20) # (500, 3500, 500)
delta = np.arange(20, 220, 20) # (500, 3500, 500)
combinations = list(itertools.product(trailing_stop_percents, fixed_stop_loss_percents, duiji, cout_delta, delta))
combinations = [(tsp, fslp, d, cd, dl, csv_file) for tsp, fslp, d, cd, dl in combinations]
with multiprocessing.Pool(processes=multiprocessing.cpu_count()) as pool:
results = pool.map(run_backtest, combinations)
best_value = 0
best_parameters = None
for value, params in results:
if value > best_value:
best_value = value
best_parameters = params
print(f"combo: {params}, value: {value}, best_value: {best_value}, best_parameters: {best_parameters}")
print(f"最佳参数组合: 跟踪止损百分比 {best_parameters[0]}%, 固定止损百分比 {best_parameters[1]}%")
print(f"最大市值: {best_value}")

View File

@@ -0,0 +1,291 @@
import backtrader as bt
from datetime import datetime
from datetime import time as s_time
from backtrader.feeds import GenericCSVData
import numpy as np
import pandas as pd
import itertools
import multiprocessing
import talib as tb
class GenericCSV_SIG(GenericCSVData):
lines = ("sig", "delta")
params = (("sig", 6), ("delta", 8))
class MyStrategy_固定止损_跟踪止盈(bt.Strategy):
params = (
("trailing_stop_percent", 0.02),
("fixed_stop_loss_percent", 0.01),
("duiji", 1),
("cout_delta", 1),
("delta", 1),
)
def __init__(self):
self.Lots = 1
self.signal = self.datas[0].sig
self.delta = self.datas[0].delta
self.pos = 0
self.high = self.datas[0].high
self.low = self.datas[0].low
self.closes = self.datas[0].close
self.open = self.datas[0].open
self.trailing_stop_percent = self.params.trailing_stop_percent
self.short_trailing_stop_price = 0
self.long_trailing_stop_price = 0
self.fixed_stop_loss_percent = self.params.fixed_stop_loss_percent
self.sl_long_price = 0
self.sl_shor_price = 0
self.out_long = 0
self.out_short = 0
self.rinei_ma = []
self.renei_high_ma = []
self.renei_low_ma = []
self.rinei_mean = 0
self.reniei_aroon_up = []
self.reniei_aroon_down = []
self.datetime_list = []
self.high_list = []
self.low_list = []
self.close_list = []
self.opens_list = []
self.deltas_list = []
self.delta_cumsum = []
self.barN = 0
def log(self, txt, dt=None):
dt = dt or self.datas[0].datetime.date(0)
print("%s, %s" % (dt.isoformat(), txt))
def next(self):
self.barN += 1
position = self.getposition(self.datas[0]).size
dt = bt.num2date(self.data.datetime[0])
def 每日重置数据():
current_time = dt.time()
clearing_time1_start = s_time(14, 55)
clearing_time1_end = s_time(15, 0)
clearing_time2_start = s_time(2, 25)
clearing_time2_end = s_time(2, 30)
clearing_executed = False
if clearing_time1_start <= current_time <= clearing_time1_end and not clearing_executed:
clearing_executed = True
self.rinei_ma = []
self.renei_high_ma = []
self.renei_low_ma = []
self.delta_cumsum = []
self.deltas_list = []
elif clearing_time2_start <= current_time <= clearing_time2_end and not clearing_executed:
clearing_executed = True
self.rinei_ma = []
self.renei_high_ma = []
self.renei_low_ma = []
self.delta_cumsum = []
self.deltas_list = []
else:
self.rinei_ma.append(self.closes[0])
self.renei_high_ma.append(self.high[0])
self.renei_low_ma.append(self.low[0])
self.rinei_mean = np.mean(self.rinei_ma)
self.reniei_aroon_up, self.reniei_aroon_down = tb.AROON(
np.array(self.renei_high_ma), np.array(self.renei_low_ma), 14
)
clearing_executed = False
return clearing_executed
run_kg = 每日重置数据()
if self.data.volume[0] <= 0:
return
if self.long_trailing_stop_price > 0 and self.pos > 0:
self.long_trailing_stop_price = max(self.low[0], self.long_trailing_stop_price)
if self.short_trailing_stop_price > 0 and self.pos < 0:
self.short_trailing_stop_price = min(self.high[0], self.short_trailing_stop_price)
self.out_long = self.long_trailing_stop_price * (1 - self.trailing_stop_percent)
self.out_short = self.short_trailing_stop_price * (1 + self.trailing_stop_percent)
if (
self.out_long > 0
and self.low[0] < self.out_long
and self.pos > 0
and self.sl_long_price > 0
and self.low[0] > self.sl_long_price
):
self.close(data=self.data, price=self.data.close[0], size=self.Lots, exectype=bt.Order.Market)
self.long_trailing_stop_price = 0
self.sl_long_price = 0
self.out_long = 0
self.pos = 0
if (
self.out_short > 0
and self.high[0] > self.out_short
and self.pos < 0
and self.sl_shor_price > 0
and self.high[0] < self.sl_shor_price
):
self.close(data=self.data, price=self.data.close[0], size=self.Lots, exectype=bt.Order.Market)
self.short_trailing_stop_price = 0
self.sl_shor_price = 0
self.out_short = 0
self.pos = 0
self.fixed_stop_loss_L = self.sl_long_price * (1 - self.fixed_stop_loss_percent)
if (
self.sl_long_price > 0
and self.fixed_stop_loss_L > 0
and self.pos > 0
and self.closes[0] < self.fixed_stop_loss_L
):
self.close(data=self.data, price=self.data.close[0], size=self.Lots, exectype=bt.Order.Market)
self.long_trailing_stop_price = 0
self.sl_long_price = 0
self.out_long = 0
self.pos = 0
self.fixed_stop_loss_S = self.sl_shor_price * (1 + self.fixed_stop_loss_percent)
if (
self.sl_shor_price > 0
and self.fixed_stop_loss_S > 0
and self.pos < 0
and self.closes[0] > self.fixed_stop_loss_S
):
self.close(data=self.data, price=self.data.close[0], size=self.Lots, exectype=bt.Order.Market)
self.short_trailing_stop_price = 0
self.sl_shor_price = 0
self.out_short = 0
self.pos = 0
self.datetime_list.append(dt)
self.high_list.append(self.data.high[0])
self.low_list.append(self.data.low[0])
self.close_list.append(self.data.close[0])
self.opens_list.append(self.data.open[0])
self.deltas_list.append(self.data.delta[0])
self.delta_cumsum.append(sum(self.deltas_list))
if run_kg == False:
# 开多组合 = self.rinei_mean > 0 and self.closes[0] > self.rinei_mean and self.signal[0] > self.params.duiji and self.data.delta[0] > self.params.delta and self.delta_cumsum[-1] > self.params.cout_delta
# 开空组合 = self.rinei_mean > 0 and self.closes[0] < self.rinei_mean and self.signal[0] < -self.params.duiji and self.data.delta[0] < -self.params.delta and self.delta_cumsum[-1] < -self.params.cout_delta
开多组合 = (
# self.reniei_aroon_up[-1] > 50
self.reniei_aroon_up[-1] > self.reniei_aroon_down[-1]
and self.signal[0] > self.params.duiji
and self.data.delta[0] > self.params.delta
and self.delta_cumsum[-1] > self.params.cout_delta
)
开空组合 = (
# self.reniei_aroon_down[-1] > 50
self.reniei_aroon_up[-1] < self.reniei_aroon_down[-1]
and self.signal[0] < -self.params.duiji
and self.data.delta[0] < -self.params.delta
and self.delta_cumsum[-1] < -self.params.cout_delta
)
平多条件 = self.pos < 0 and self.signal[0] > self.params.duiji
平空条件 = self.pos > 0 and self.signal[0] < -self.params.duiji
if self.pos != 1:
if 平多条件:
self.close(data=self.data, price=self.data.close[0], exectype=bt.Order.Market)
self.short_trailing_stop_price = 0
self.sl_shor_price = 0
self.out_short = 0
self.pos = 0
if 开多组合:
self.buy(data=self.data, price=self.data.close[0], size=1, exectype=bt.Order.Market)
self.pos = 1
self.long_trailing_stop_price = self.low[0]
self.sl_long_price = self.data.open[0]
if self.pos != -1:
if 平空条件:
self.close(data=self.data, price=self.data.close[0], exectype=bt.Order.Market)
self.long_trailing_stop_price = 0
self.sl_long_price = 0
self.out_long = 0
self.pos = 0
if 开空组合:
self.sell(data=self.data, price=self.data.close[0], size=1, exectype=bt.Order.Market)
self.pos = -1
self.short_trailing_stop_price = self.high[0]
self.sl_shor_price = self.data.open[0]
def evaluate_strategy(trailing_stop_percent, fixed_stop_loss_percent, duiji, cout_delta, delta, csv_file):
cerebro = bt.Cerebro()
cerebro.addstrategy(
MyStrategy_固定止损_跟踪止盈,
trailing_stop_percent=trailing_stop_percent,
fixed_stop_loss_percent=fixed_stop_loss_percent,
duiji=duiji,
cout_delta=cout_delta,
delta=delta,
)
data = GenericCSV_SIG(
dataname=csv_file,
fromdate=datetime(2020, 1, 1),
todate=datetime(2023, 12, 29),
timeframe=bt.TimeFrame.Minutes,
nullvalue=0.0,
dtformat="%Y-%m-%d %H:%M:%S",
datetime=0,
high=3,
low=4,
open=2,
close=1,
volume=5,
openinterest=None,
sig=6,
delta=8,
)
cerebro.adddata(data)
cerebro.broker.setcash(300000.0)
cerebro.broker.setcommission(commission=14, margin=150000.0, mult=300)
cerebro.run()
return cerebro.broker.getvalue(), (trailing_stop_percent, fixed_stop_loss_percent, duiji, cout_delta, delta)
def run_backtest(params):
trailing_stop_percent, fixed_stop_loss_percent, duiji, cout_delta, delta, csv_file = params
return evaluate_strategy(trailing_stop_percent, fixed_stop_loss_percent, duiji, cout_delta, delta, csv_file)
if __name__ == "__main__":
csv_file = r"D:\BaiduNetdiskDownload\主力连续\tick生成的OF数据(5M)\data_rs_merged\中金所\IM888\IM888_rs_2023_5T_back_ofdata_dj.csv"
trailing_stop_percents = np.arange(0.005, 0.025, 0.005)
fixed_stop_loss_percents = np.arange(0.01, 0.050, 0.01)
duiji = np.arange(1, 4, 1)
cout_delta = np.arange(100000, 800000, 100000) # (500, 3500, 500)
delta = np.arange(100000, 800000, 100000) # (500, 3500, 500)
combinations = list(itertools.product(trailing_stop_percents, fixed_stop_loss_percents, duiji, cout_delta, delta))
combinations = [(tsp, fslp, d, cd, dl, csv_file) for tsp, fslp, d, cd, dl in combinations]
with multiprocessing.Pool(processes=multiprocessing.cpu_count()) as pool:
results = pool.map(run_backtest, combinations)
best_value = 0
best_parameters = None
for value, params in results:
if value > best_value:
best_value = value
best_parameters = params
print(f"combo: {params}, value: {value}, best_value: {best_value}, best_parameters: {best_parameters}")
print(f"最佳参数组合: 跟踪止损百分比 {best_parameters[0]}%, 固定止损百分比 {best_parameters[1]}%")
print(f"最大市值: {best_value}")
# trailing_stop_percent, fixed_stop_loss_percent, duiji, cout_delta, delta
# IM
# 5M(0.01, 0.02, 2, 700000, 500000)
# 1M(0.005, 0.02, 3, 100000, 200000)
# IF
# 5M(0.005, 0.02, 1, 100000, 400000)

View File

@@ -0,0 +1,307 @@
import backtrader as bt
from datetime import datetime
from datetime import time as s_time
from backtrader.feeds import GenericCSVData
import numpy as np
import pandas as pd
import itertools
import multiprocessing
import talib as tb
class GenericCSV_SIG(GenericCSVData):
lines = ("sig", "delta")
params = (("sig", 6), ("delta", 8))
class MyStrategy_固定止损_跟踪止盈(bt.Strategy):
params = (
("trailing_stop_percent", 0.02),
("fixed_stop_loss_percent", 0.01),
("duiji", 1),
("cout_delta", 1),
("delta", 1),
("aroon_timeperiod", 14),
)
def __init__(self):
self.Lots = 1
self.signal = self.datas[0].sig
self.delta = self.datas[0].delta
self.pos = 0
self.high = self.datas[0].high
self.low = self.datas[0].low
self.closes = self.datas[0].close
self.open = self.datas[0].open
self.trailing_stop_percent = self.params.trailing_stop_percent
self.short_trailing_stop_price = 0
self.long_trailing_stop_price = 0
self.fixed_stop_loss_percent = self.params.fixed_stop_loss_percent
self.sl_long_price = 0
self.sl_shor_price = 0
self.out_long = 0
self.out_short = 0
self.rinei_ma = []
self.renei_high_ma = []
self.renei_low_ma = []
self.rinei_mean = 0
self.reniei_aroon_up = []
self.reniei_aroon_down = []
self.datetime_list = []
self.high_list = []
self.low_list = []
self.close_list = []
self.opens_list = []
self.deltas_list = []
self.delta_cumsum = []
self.barN = 0
def log(self, txt, dt=None):
dt = dt or self.datas[0].datetime.date(0)
print("%s, %s" % (dt.isoformat(), txt))
def next(self):
self.barN += 1
position = self.getposition(self.datas[0]).size
dt = bt.num2date(self.data.datetime[0])
def 每日重置数据():
current_time = dt.time()
clearing_time1_start = s_time(14, 55)
clearing_time1_end = s_time(15, 0)
clearing_time2_start = s_time(2, 25)
clearing_time2_end = s_time(2, 30)
clearing_executed = False
if clearing_time1_start <= current_time <= clearing_time1_end and not clearing_executed:
clearing_executed = True
self.rinei_ma = []
self.renei_high_ma = []
self.renei_low_ma = []
self.delta_cumsum = []
self.deltas_list = []
elif clearing_time2_start <= current_time <= clearing_time2_end and not clearing_executed:
clearing_executed = True
self.rinei_ma = []
self.renei_high_ma = []
self.renei_low_ma = []
self.delta_cumsum = []
self.deltas_list = []
else:
self.rinei_ma.append(self.closes[0])
self.renei_high_ma.append(self.high[0])
self.renei_low_ma.append(self.low[0])
self.rinei_mean = np.mean(self.rinei_ma)
self.reniei_aroon_up, self.reniei_aroon_down = tb.AROON(
np.array(self.renei_high_ma), np.array(self.renei_low_ma), self.params.aroon_timeperiod
)
clearing_executed = False
return clearing_executed
run_kg = 每日重置数据()
if self.data.volume[0] <= 0:
return
if self.long_trailing_stop_price > 0 and self.pos > 0:
self.long_trailing_stop_price = max(self.low[0], self.long_trailing_stop_price)
if self.short_trailing_stop_price > 0 and self.pos < 0:
self.short_trailing_stop_price = min(self.high[0], self.short_trailing_stop_price)
self.out_long = self.long_trailing_stop_price * (1 - self.trailing_stop_percent)
self.out_short = self.short_trailing_stop_price * (1 + self.trailing_stop_percent)
if (
self.out_long > 0
and self.low[0] < self.out_long
and self.pos > 0
and self.sl_long_price > 0
and self.low[0] > self.sl_long_price
):
self.close(data=self.data, price=self.data.close[0], size=self.Lots, exectype=bt.Order.Market)
self.long_trailing_stop_price = 0
self.sl_long_price = 0
self.out_long = 0
self.pos = 0
if (
self.out_short > 0
and self.high[0] > self.out_short
and self.pos < 0
and self.sl_shor_price > 0
and self.high[0] < self.sl_shor_price
):
self.close(data=self.data, price=self.data.close[0], size=self.Lots, exectype=bt.Order.Market)
self.short_trailing_stop_price = 0
self.sl_shor_price = 0
self.out_short = 0
self.pos = 0
self.fixed_stop_loss_L = self.sl_long_price * (1 - self.fixed_stop_loss_percent)
if (
self.sl_long_price > 0
and self.fixed_stop_loss_L > 0
and self.pos > 0
and self.closes[0] < self.fixed_stop_loss_L
):
self.close(data=self.data, price=self.data.close[0], size=self.Lots, exectype=bt.Order.Market)
self.long_trailing_stop_price = 0
self.sl_long_price = 0
self.out_long = 0
self.pos = 0
self.fixed_stop_loss_S = self.sl_shor_price * (1 + self.fixed_stop_loss_percent)
if (
self.sl_shor_price > 0
and self.fixed_stop_loss_S > 0
and self.pos < 0
and self.closes[0] > self.fixed_stop_loss_S
):
self.close(data=self.data, price=self.data.close[0], size=self.Lots, exectype=bt.Order.Market)
self.short_trailing_stop_price = 0
self.sl_shor_price = 0
self.out_short = 0
self.pos = 0
self.datetime_list.append(dt)
self.high_list.append(self.data.high[0])
self.low_list.append(self.data.low[0])
self.close_list.append(self.data.close[0])
self.opens_list.append(self.data.open[0])
self.deltas_list.append(self.data.delta[0])
self.delta_cumsum.append(sum(self.deltas_list))
if run_kg == False:
# 开多组合 = self.rinei_mean > 0 and self.closes[0] > self.rinei_mean and self.signal[0] > self.params.duiji and self.data.delta[0] > self.params.delta and self.delta_cumsum[-1] > self.params.cout_delta
# 开空组合 = self.rinei_mean > 0 and self.closes[0] < self.rinei_mean and self.signal[0] < -self.params.duiji and self.data.delta[0] < -self.params.delta and self.delta_cumsum[-1] < -self.params.cout_delta
开多组合 = (
# self.reniei_aroon_up[-1] > 50
self.reniei_aroon_up[-1] > self.reniei_aroon_down[-1]
and self.signal[0] > self.params.duiji
and self.data.delta[0] > self.params.delta
and self.delta_cumsum[-1] > self.params.cout_delta
)
开空组合 = (
# self.reniei_aroon_down[-1] > 50
self.reniei_aroon_up[-1] < self.reniei_aroon_down[-1]
and self.signal[0] < -self.params.duiji
and self.data.delta[0] < -self.params.delta
and self.delta_cumsum[-1] < -self.params.cout_delta
)
平多条件 = self.pos < 0 and self.signal[0] > self.params.duiji
平空条件 = self.pos > 0 and self.signal[0] < -self.params.duiji
if self.pos != 1:
if 平多条件:
self.close(data=self.data, price=self.data.close[0], exectype=bt.Order.Market)
self.short_trailing_stop_price = 0
self.sl_shor_price = 0
self.out_short = 0
self.pos = 0
if 开多组合:
self.buy(data=self.data, price=self.data.close[0], size=1, exectype=bt.Order.Market)
self.pos = 1
self.long_trailing_stop_price = self.low[0]
self.sl_long_price = self.data.open[0]
if self.pos != -1:
if 平空条件:
self.close(data=self.data, price=self.data.close[0], exectype=bt.Order.Market)
self.long_trailing_stop_price = 0
self.sl_long_price = 0
self.out_long = 0
self.pos = 0
if 开空组合:
self.sell(data=self.data, price=self.data.close[0], size=1, exectype=bt.Order.Market)
self.pos = -1
self.short_trailing_stop_price = self.high[0]
self.sl_shor_price = self.data.open[0]
def evaluate_strategy(
trailing_stop_percent, fixed_stop_loss_percent, duiji, cout_delta, delta, aroon_timeperiod, csv_file
):
cerebro = bt.Cerebro()
cerebro.addstrategy(
MyStrategy_固定止损_跟踪止盈,
trailing_stop_percent=trailing_stop_percent,
fixed_stop_loss_percent=fixed_stop_loss_percent,
duiji=duiji,
cout_delta=cout_delta,
delta=delta,
aroon_timeperiod=aroon_timeperiod,
)
data = GenericCSV_SIG(
dataname=csv_file,
fromdate=datetime(2022, 1, 1),
todate=datetime(2022, 12, 29),
timeframe=bt.TimeFrame.Minutes,
nullvalue=0.0,
dtformat="%Y-%m-%d %H:%M:%S",
datetime=0,
high=3,
low=4,
open=2,
close=1,
volume=5,
openinterest=None,
sig=6,
delta=8,
)
cerebro.adddata(data)
cerebro.broker.setcash(300000.0)
cerebro.broker.setcommission(commission=14, margin=150000.0, mult=300)
cerebro.run()
return cerebro.broker.getvalue(), (
trailing_stop_percent,
fixed_stop_loss_percent,
duiji,
cout_delta,
delta,
aroon_timeperiod,
)
def run_backtest(params):
trailing_stop_percent, fixed_stop_loss_percent, duiji, cout_delta, delta, aroon_timeperiod, csv_file = params
return evaluate_strategy(
trailing_stop_percent, fixed_stop_loss_percent, duiji, cout_delta, delta, aroon_timeperiod, csv_file
)
if __name__ == "__main__":
csv_file = r"D:\BaiduNetdiskDownload\主力连续\tick生成的OF数据(2M)\data_rs_merged\中金所\IM888\IM888_rs_2022_2T_back_ofdata_dj_new.csv"
trailing_stop_percents = np.arange(0.005, 0.025, 0.005)
fixed_stop_loss_percents = np.arange(0.01, 0.030, 0.01)
duiji = np.arange(2, 4, 1)
cout_delta = np.arange(500000, 4000000, 500000) # (500, 3500, 500)
delta = np.arange(500000, 4000000, 500000) # (500, 3500, 500)
aroon_timeperiod = np.arange(4, 20, 4)
combinations = list(
itertools.product(trailing_stop_percents, fixed_stop_loss_percents, duiji, cout_delta, delta, aroon_timeperiod)
)
combinations = [(tsp, fslp, d, cd, dl, d2, csv_file) for tsp, fslp, d, cd, dl, d2 in combinations]
with multiprocessing.Pool(processes=multiprocessing.cpu_count()) as pool:
results = pool.map(run_backtest, combinations)
best_value = 0
best_parameters = None
for value, params in results:
if value > best_value:
best_value = value
best_parameters = params
print(f"combo: {params}, value: {value}, best_value: {best_value}, best_parameters: {best_parameters}")
print(f"最佳参数组合: 跟踪止损百分比 {best_parameters[0]}%, 固定止损百分比 {best_parameters[1]}%")
print(f"最大市值: {best_value}")
# trailing_stop_percent, fixed_stop_loss_percent, duiji, cout_delta, delta
# IM
# 5M(0.01, 0.02, 2, 700000, 500000)
# 1M(0.005, 0.02, 3, 100000, 200000)
# IF
# 5M(0.005, 0.02, 1, 100000, 400000)

View File

@@ -0,0 +1,422 @@
'''
以下是代码的详细说明:
#公众号松鼠Quant
#主页www.quant789.com
#本策略仅作学习交流使用,实盘交易盈亏投资者个人负责!!!
#版权归松鼠Quant所有禁止转发、转卖源码违者必究。
1.
导入必要的模块和库:
backtrader 用于回测功能
datetime 用于处理日期和时间
GenericCSVData 用于从CSV文件加载数据
numpy 用于数值操作
time 用于时间相关操作
matplotlib.pyplot 用于绘图
2. 定义自定义手续费模板MyCommission
继承自bt.CommInfoBase
3.
定义自定义数据源类 GenericCSV_SIG
继承自 GenericCSVData并添加了两个额外的行'sig''delta'
定义了参数 'sig''delta'
4.
定义 MyStrategy_固定止损_跟踪止盈 类:
继承自 bt.Strategybacktrader的基础策略类
定义了两个参数trailing_stop_percent 和 fixed_stop_loss_percent
初始化策略并设置各种变量和指标
实现了 next 方法该方法在数据源的每个新的K线出现时被调用
根据当前K线数据更新跟踪止盈价格
实现了跟踪止盈出场和固定止损出场
根据信号处理多头和空头仓位
在策略执行过程中打印调试信息
5.
if __name__ == "__main__": 代码块:
使用 Cerebro 实例设置回测环境
使用 GenericCSV_SIG 数据源从CSV文件加载数据
将数据源和策略添加到 Cerebro 实例中
添加观察者和分析器以评估性能
设置初始资金和经纪人参数
运行回测并获取结果
打印回测报告,包括收益率、回撤、胜率和交易统计数据
使用 matplotlib 绘制回测结果
#公众号松鼠Quant
#主页www.quant789.com
#本策略仅作学习交流使用,实盘交易盈亏投资者个人负责!!!
#版权归松鼠Quant所有禁止转发、转卖源码违者必究。
'''
import backtrader as bt
from datetime import datetime
from datetime import time as s_time
from backtrader.feeds import GenericCSVData
import numpy as np
import pandas as pd
import time
import matplotlib.pyplot as plt
import os
import itertools
from scipy.optimize import brute
import talib as tb
手续费汇总=0
class GenericCSV_SIG(GenericCSVData):
# 从基类继承,添加一个 'sig'delta
lines = ('sig','delta')
# 添加参数为从基类继承的参数
params = (('sig',6),('delta', 8))
class MyStrategy_固定止损_跟踪止盈(bt.Strategy):
params = (
('trailing_stop_percent', 0.02), # 跟踪止盈百分比
('fixed_stop_loss_percent', 0.01), # 固定止损百分比
('duiji', 1), # 堆积
('cout_delta', 1), # 日累计delta
('delta', 1), # delta单bar
)
def __init__(self):
self.Lots=1 #下单手数
self.signal = self.datas[0].sig # 使用sig字段作为策略的信号字段
self.delta= self.datas[0].delta
# 获取数据序列别名列表
line_aliases = self.datas[0].getlinealiases()
self.pos=0
print(line_aliases)
self.high=self.datas[0].high
self.low=self.datas[0].low
self.closes=self.datas[0].close
self.open=self.datas[0].open
self.trailing_stop_percent = self.params.trailing_stop_percent
self.short_trailing_stop_price = 0
self.long_trailing_stop_price = 0
self.fixed_stop_loss_percent = self.params.fixed_stop_loss_percent
self.sl_long_price=0
self.sl_shor_price=0
self.out_long=0
self.out_short=0
self.rinei_ma=[]
self.rinei_mean=0
self.renei_high_ma = []
self.renei_low_ma = []
self.reniei_aroon_up = []
self.reniei_aroon_down = []
self.datetime_list= []
self.high_list = []
self.low_list = []
self.close_list = []
self.opens_list = []
self.deltas_list = []
self.delta_cumsum=[]
self.barN = 0
self.df = pd.DataFrame(columns=['datetime', 'high', 'low', 'close', 'open', 'delta', 'delta_cumsum'])
self.trader_df=pd.DataFrame(columns=['open', 'high', 'low', 'close', 'volume', 'openInterest','delta'])
def log(self, txt, dt=None):
'''可选,构建策略打印日志的函数:可用于打印订单记录或交易记录等'''
dt = dt or self.datas[0].datetime.date(0)
print('%s, %s' % (dt.isoformat(), txt))
# def notify_order(self, order):
# # 未被处理的订单
# if order.status in [order.Submitted, order.Accepted]:
# return
# # 已经处理的订单
# if order.status in [order.Completed, order.Canceled, order.Margin]:
# global 手续费汇总
# if order.isbuy():
# 手续费汇总 +=order.executed.comm
# self.log(
# 'BUY EXECUTED, 订单编号:%.0f,成交价格: %.2f, 手续费滑点:%.2f, 成交量: %.2f, 品种: %s,手续费汇总:%.2f' %
# (order.ref, # 订单编号
# order.executed.price, # 成交价
# order.executed.comm, # 佣金
# order.executed.size, # 成交量
# order.data._name,# 品种名称
# 手续费汇总))
# else: # Sell
# 手续费汇总 +=order.executed.comm
# self.log('SELL EXECUTED, 订单编号:%.0f,成交价格: %.2f, 手续费滑点:%.2f, 成交量: %.2f, 品种: %s,手续费汇总:%.2f' %
# (order.ref,
# order.executed.price,
# order.executed.comm,
# order.executed.size,
# order.data._name,
# 手续费汇总))
def next(self):
#公众号松鼠Quant
#主页www.quant789.com
#本策略仅作学习交流使用,实盘交易盈亏投资者个人负责!!!
#版权归松鼠Quant所有禁止转发、转卖源码违者必究。
#bar线计数初始化
self.barN += 1
position = self.getposition(self.datas[0]).size
#时间轴
dt = bt.num2date(self.data.datetime[0])
#更新跟踪止损价格
def 每日重置数据():
# 获取当前时间
current_time = dt.time()
#print(current_time)
# 设置清仓操作的时间范围114:55到15:00
clearing_time1_start = s_time(14, 55)
clearing_time1_end = s_time(15, 0)
# 设置清仓操作的时间范围200:55到01:00
clearing_time2_start = s_time(2, 25)
clearing_time2_end = s_time(2, 30)
# 创建一个标志变量
clearing_executed = False
if clearing_time1_start <= current_time <= clearing_time1_end and not clearing_executed :
clearing_executed = True # 设置标志变量为已执行
self.rinei_ma=[]
self.renei_high_ma = []
self.renei_low_ma = []
self.delta_cumsum=[]
self.deltas_list=[]
elif clearing_time2_start <= current_time <= clearing_time2_end and not clearing_executed :
clearing_executed = True # 设置标志变量为已执行
self.rinei_ma=[]
self.renei_high_ma = []
self.renei_low_ma = []
self.delta_cumsum=[]
self.deltas_list=[]
# 如果不在任何时间范围内,可以执行其他操作
else:
self.rinei_ma.append(self.closes[0])
self.rinei_mean = np.mean(self.rinei_ma)
self.renei_high_ma.append(self.high[0])
self.renei_low_ma.append(self.low[0])
self.rinei_mean = np.mean(self.rinei_ma)
self.reniei_aroon_up, self.reniei_aroon_down = tb.AROON(np.array(self.renei_high_ma), np.array(self.renei_low_ma), 14)
#self.delta_cumsum=[]
#self.deltas_list=[]
#print('rinei_ma',self.rinei_ma)
clearing_executed = False
pass
return clearing_executed
run_kg=每日重置数据()
#过滤成交量为0或小于0
if self.data.volume[0] <= 0 :
return
#print(f'volume,{self.data.volume[0]}')
if self.long_trailing_stop_price >0 and self.pos>0:
#print('datetime+sig: ',dt,'旧多头出线',self.long_trailing_stop_price,'low',self.low[0])
self.long_trailing_stop_price = self.low[0] if self.long_trailing_stop_price<self.low[0] else self.long_trailing_stop_price
#print('datetime+sig: ',dt,'多头出线',self.long_trailing_stop_price)
if self.short_trailing_stop_price >0 and self.pos<0:
#print('datetime+sig: ',dt,'旧空头出线',self.short_trailing_stop_price,'high',self.high[0])
self.short_trailing_stop_price = self.high[0] if self.high[0] <self.short_trailing_stop_price else self.short_trailing_stop_price
#print('datetime+sig: ',dt,'空头出线',self.short_trailing_stop_price)
self.out_long=self.long_trailing_stop_price * (1 - self.trailing_stop_percent)
self.out_short=self.short_trailing_stop_price*(1 + self.trailing_stop_percent)
#print('datetime+sig: ',dt,'空头出线',self.out_short)
#print('datetime+sig: ',dt,'多头出线',self.out_long)
# 跟踪出场
if self.out_long >0:
if self.low[0] < self.out_long and self.pos>0 and self.sl_long_price>0 and self.low[0]>self.sl_long_price:
#print('--多头止盈出场datetime+sig: ',dt,'Trailing stop triggered: Closing position','TR',self.out_long,'low', self.low[0])
self.close(data=self.data, price=self.data.close[0],size=self.Lots, exectype=bt.Order.Market)
self.long_trailing_stop_price = 0
self.sl_long_price=0
self.out_long=0
self.pos = 0
if self.out_short>0:
if self.high[0] > self.out_short and self.pos<0 and self.sl_shor_price>0 and self.high[0]<self.sl_shor_price:
#print('--空头止盈出场datetime+sig: ',dt,'Trailing stop triggered: Closing position: ','TR',self.out_short,'high', self.high[0])
self.close(data=self.data, price=self.data.close[0],size=self.Lots, exectype=bt.Order.Market)
self.short_trailing_stop_price = 0
self.sl_shor_price=0
self.out_shor=0
self.pos = 0
# 固定止损
self.fixed_stop_loss_L = self.sl_long_price * (1 - self.fixed_stop_loss_percent)
if self.sl_long_price>0 and self.fixed_stop_loss_L>0 and self.pos > 0 and self.closes[0] < self.fixed_stop_loss_L:
#print('--多头止损datetime+sig: ', dt, 'Fixed stop loss triggered: Closing position', 'SL', self.fixed_stop_loss_L, 'close', self.closes[0])
self.close(data=self.data, price=self.data.close[0],size=self.Lots, exectype=bt.Order.Market)
self.long_trailing_stop_price = 0
self.sl_long_price=0
self.out_long = 0
self.pos = 0
self.fixed_stop_loss_S = self.sl_shor_price * (1 + self.fixed_stop_loss_percent)
if self.sl_shor_price>0 and self.fixed_stop_loss_S>0 and self.pos < 0 and self.closes[0] > self.fixed_stop_loss_S:
#print('--空头止损datetime+sig: ', dt, 'Fixed stop loss triggered: Closing position', 'SL', self.fixed_stop_loss_S, 'close', self.closes[0])
self.close(data=self.data, price=self.data.close[0], size=self.Lots,exectype=bt.Order.Market)
self.short_trailing_stop_price = 0
self.sl_shor_price=0
self.out_short = 0
self.pos = 0
# 更新最高价和最低价的列表
self.datetime_list.append(dt)
self.high_list.append(self.data.high[0])
self.low_list.append(self.data.low[0])
self.close_list.append(self.data.close[0])
self.opens_list.append(self.data.open[0])
self.deltas_list.append(self.data.delta[0])
# 计算delta累计
self.delta_cumsum.append(sum(self.deltas_list))
# 将当前行数据添加到 DataFrame
# new_row = {
# 'datetime': dt,
# 'high': self.data.high[0],
# 'low': self.data.low[0],
# 'close': self.data.close[0],
# 'open': self.data.open[0],
# 'delta': self.data.delta[0],
# 'delta_cumsum': sum(self.deltas_list)
# }
# # 使用pandas.concat代替append
# self.df = pd.concat([self.df, pd.DataFrame([new_row])], ignore_index=True)
# # 检查文件是否存在
# csv_file_path = f"output.csv"
# if os.path.exists(csv_file_path):
# # 仅保存最后一行数据
# self.df.tail(1).to_csv(csv_file_path, mode='a', header=False, index=False)
# else:
# # 创建新文件并保存整个DataFrame
# self.df.to_csv(csv_file_path, index=False)
#
if run_kg==False : #
#print(self.delta_cumsum)
# 开多组合= self.rinei_mean>0 and self.closes[0]>self.rinei_mean and self.signal[0] >self.params.duiji and self.data.delta[0]>self.params.delta and self.delta_cumsum[-1]>self.params.cout_delta
# 开空组合= self.rinei_mean>0 and self.closes[0]<self.rinei_mean and self.signal[0] <-self.params.duiji and self.data.delta[0]<-self.params.delta and self.delta_cumsum[-1]<-self.params.cout_delta
开多组合 = self.reniei_aroon_up[-1] > 50 and self.reniei_aroon_up[-1] > self.reniei_aroon_down[-1] and self.signal[0] > self.params.duiji and self.data.delta[0] > self.params.delta and self.delta_cumsum[-1] > self.params.cout_delta
开空组合 = self.reniei_aroon_down[-1] > 50 and self.reniei_aroon_up[-1] < self.reniei_aroon_down[-1] and self.signal[0] < -self.params.duiji and self.data.delta[0] < -self.params.delta and self.delta_cumsum[-1] < -self.params.cout_delta
平多条件=self.pos<0 and self.signal[0] >self.params.duiji
平空条件=self.pos>0 and self.signal[0] <-self.params.duiji
if self.pos !=1 : #
if 平多条件:
#print('datetime+sig: ', dt, 'Fixed stop loss triggered: Closing position', 'SL', self.fixed_stop_loss_S, 'close', self.closes[0])
self.close(data=self.data, price=self.data.close[0], exectype=bt.Order.Market)
self.short_trailing_stop_price = 0
self.sl_shor_price=0
self.out_short = 0
self.pos = 0
if 开多组合 : #
self.buy(data=self.data, price=self.data.close[0], size=1, exectype=bt.Order.Market)
self.pos=1
self.long_trailing_stop_price=self.low[0]
self.sl_long_price=self.data.open[0]
#print('datetime+sig: ',dt,' sig: ',self.signal[0],'保存多头价格: ',self.long_trailing_stop_price)
if self.pos !=-1 : #
if 平空条件:
#print('datetime+sig: ', dt, 'Fixed stop loss triggered: Closing position', 'SL', self.fixed_stop_loss_L, 'close', self.closes[0])
self.close(data=self.data, price=self.data.close[0], exectype=bt.Order.Market)
self.long_trailing_stop_price = 0
self.sl_long_price=0
self.out_long = 0
self.pos = 0
if 开空组合: #
self.sell(data=self.data, price=self.data.close[0], size=1, exectype=bt.Order.Market)
self.pos=-1
self.short_trailing_stop_price=self.high[0]
self.sl_shor_price=self.data.open[0]
#print('datetime+sig: ',dt,' sig: ',self.signal[0],'保存空头价格: ',self.short_trailing_stop_price)
if __name__ == "__main__":
#公众号松鼠Quant
#主页www.quant789.com
#本策略仅作学习交流使用,实盘交易盈亏投资者个人负责!!!
#版权归松鼠Quant所有禁止转发、转卖源码违者必究。
# 创建Cerebro实例
cerebro = bt.Cerebro()
#数据
csv_file='E:/of_data/主力连续/tick生成的OF数据(1M)/data_rs_merged/上期所/ag888/ag888_rs_2023_1T_back_ofdata_dj.csv' #
# 从CSV文件加载数据
data = GenericCSV_SIG(
dataname=csv_file,
fromdate=datetime(2023,1,1),
todate=datetime(2023,12,29),
timeframe=bt.TimeFrame.Minutes,
nullvalue=0.0,
dtformat='%Y-%m-%d %H:%M:%S',
datetime=0,
high=3,
low=4,
open=2,
close=1,
volume=5,
openinterest=None,
sig=6,
delta=8
)
# 评估函数,输入参数,返回评估函数值,这里是总市值,要求最大化
def evaluate_strategy(trailing_stop_percent, fixed_stop_loss_percent,duiji,cout_delta,delta):
cerebro = bt.Cerebro()
cerebro.addstrategy(MyStrategy_固定止损_跟踪止盈)
cerebro.adddata(data) # 确保你有一个有效的数据源
cerebro.broker.setcash(10000.0)
#手续费,单手保证金,合约倍数
cerebro.broker.setcommission(commission=14, margin=5000.0,mult=10)#回测参数
cerebro.run()
return cerebro.broker.getvalue()
# 创建参数网格
trailing_stop_percents = np.arange(0.005, 0.025, 0.005)
fixed_stop_loss_percents = np.arange(0.01, 0.050, 0.01)
duiji= np.arange(1, 3, 1) #
cout_delta= np.arange(500, 3500, 500)
delta=np.arange(500, 3500, 500)
# 生成所有参数组合
combinations = list(itertools.product(trailing_stop_percents, fixed_stop_loss_percents,duiji,cout_delta,delta))
# 评估所有参数组合并找到最佳参数
best_value = 0
best_parameters = None
for combo in combinations:
value = evaluate_strategy(*combo)
if value > best_value:
best_value = value
best_parameters = combo
print(f'combo: {combo},best_value: {best_value},best_parameters: {best_parameters}')
# 打印最佳参数组合
print(f"最佳参数组合: 跟踪止损百分比 {best_parameters[0]}%, 固定止损百分比 {best_parameters[1]}%")
print(f"最大市值: {best_value}")
#公众号松鼠Quant
#主页www.quant789.com
#本策略仅作学习交流使用,实盘交易盈亏投资者个人负责!!!

View File

@@ -0,0 +1,489 @@
"""
以下是代码的详细说明:
1.
导入必要的模块和库:
backtrader 用于回测功能
datetime 用于处理日期和时间
GenericCSVData 用于从CSV文件加载数据
numpy 用于数值操作
time 用于时间相关操作
matplotlib.pyplot 用于绘图
2. 定义自定义手续费模板MyCommission
继承自bt.CommInfoBase
3.
定义自定义数据源类 GenericCSV_SIG
继承自 GenericCSVData并添加了两个额外的行'sig''delta'
定义了参数 'sig''delta'
4.
定义 MyStrategy_固定止损_跟踪止盈 类:
继承自 bt.Strategybacktrader的基础策略类
定义了两个参数trailing_stop_percent 和 fixed_stop_loss_percent
初始化策略并设置各种变量和指标
实现了 next 方法该方法在数据源的每个新的K线出现时被调用
根据当前K线数据更新跟踪止盈价格
实现了跟踪止盈出场和固定止损出场
根据信号处理多头和空头仓位
在策略执行过程中打印调试信息
5.
if __name__ == "__main__": 代码块:
使用 Cerebro 实例设置回测环境
使用 GenericCSV_SIG 数据源从CSV文件加载数据
将数据源和策略添加到 Cerebro 实例中
添加观察者和分析器以评估性能
设置初始资金和经纪人参数
运行回测并获取结果
打印回测报告,包括收益率、回撤、胜率和交易统计数据
6.使用前事项:
1、主程序中修改ofdata_dj文件地址、png_filepath地址
2、修改clearing_time2_start、clearing_time2_stop
3、修改交易参数:lots、跟踪止损百分、固定止损百分比、duiji、cout_delta、delta
4、修改资金参数:初始资金;回测参数:回测时间段、佣金、单边保证金、手续费;
"""
import backtrader as bt
from datetime import datetime
from datetime import time as s_time
from backtrader.feeds import GenericCSVData
import numpy as np
import pandas as pd
import time
import matplotlib.pyplot as plt
import os
import talib as tb # jerom注释 增加talib库
手续费汇总 = 0
class GenericCSV_SIG(GenericCSVData):
# 从基类继承,添加一个 'sig'delta
lines = ("sig", "delta")
# 添加参数为从基类继承的参数
params = (("sig", 6), ("delta", 8))
class MyStrategy_固定止损_跟踪止盈(bt.Strategy):
params = (
("trailing_stop_percent", 0.01), # 跟踪止盈百分比
("fixed_stop_loss_percent", 0.01), # 固定止损百分比
)
def __init__(self):
self.Lots = 1 # 下单手数
self.signal = self.datas[0].sig # 使用sig字段作为策略的信号字段
self.delta = self.datas[0].delta
# 获取数据序列别名列表
line_aliases = self.datas[0].getlinealiases()
self.pos = 0
print(line_aliases)
self.high = self.datas[0].high
self.low = self.datas[0].low
self.closes = self.datas[0].close
self.open = self.datas[0].open
self.trailing_stop_percent = self.params.trailing_stop_percent
self.short_trailing_stop_price = 0
self.long_trailing_stop_price = 0
self.fixed_stop_loss_percent = self.params.fixed_stop_loss_percent
self.sl_long_price = 0
self.sl_shor_price = 0
self.out_long = 0
# 240884432
self.out_short = 0
self.rinei_ma = []
self.rinei_mean = 0
self.datetime_list = []
self.high_list = []
self.low_list = []
self.close_list = []
self.opens_list = []
self.deltas_list = []
self.delta_cumsum = []
self.barN = 0
self.df = pd.DataFrame(columns=["datetime", "high", "low", "close", "open", "delta", "delta_cumsum"])
self.trader_df = pd.DataFrame(columns=["open", "high", "low", "close", "volume", "openInterest", "delta"])
def log(self, txt, dt=None):
"""可选,构建策略打印日志的函数:可用于打印订单记录或交易记录等"""
dt = dt or self.datas[0].datetime.date(0)
print("%s, %s" % (dt.isoformat(), txt))
def notify_order(self, order):
# 未被处理的订单
if order.status in [order.Submitted, order.Accepted]:
return
# 已经处理的订单
if order.status in [order.Completed, order.Canceled, order.Margin]:
global 手续费汇总
if order.isbuy():
手续费汇总 += order.executed.comm
self.log(
"BUY EXECUTED, 订单编号:%.0f,成交价格: %.2f, 手续费滑点:%.2f, 成交量: %.2f, 品种: %s,手续费汇总:%.2f"
% (
order.ref, # 订单编号
order.executed.price, # 成交价
order.executed.comm, # 佣金
order.executed.size, # 成交量
order.data._name, # 品种名称
手续费汇总,
)
)
else: # Sell
手续费汇总 += order.executed.comm
self.log(
"SELL EXECUTED, 订单编号:%.0f,成交价格: %.2f, 手续费滑点:%.2f, 成交量: %.2f, 品种: %s,手续费汇总:%.2f"
% (
order.ref,
order.executed.price,
order.executed.comm,
order.executed.size,
order.data._name,
手续费汇总,
)
)
def next(self):
# bar线计数初始化
self.barN += 1
position = self.getposition(self.datas[0]).size
# 时间轴
dt = bt.num2date(self.data.datetime[0])
# 更新跟踪止损价格
def 每日重置数据():
# 获取当前时间
current_time = dt.time()
# print(current_time)
# 设置清仓操作的时间范围114:55到15:00
clearing_time1_start = s_time(14, 55)
clearing_time1_end = s_time(15, 0)
# 设置清仓操作的时间范围200:55到01:00
clearing_time2_start = s_time(2, 25)
clearing_time2_end = s_time(2, 30)
# 创建一个标志变量
clearing_executed = False
if clearing_time1_start <= current_time <= clearing_time1_end and not clearing_executed:
clearing_executed = True # 设置标志变量为已执行
self.rinei_ma = []
self.delta_cumsum = []
self.deltas_list = []
elif clearing_time2_start <= current_time <= clearing_time2_end and not clearing_executed:
clearing_executed = True # 设置标志变量为已执行
self.rinei_ma = []
self.delta_cumsum = []
self.deltas_list = []
# 如果不在任何时间范围内,可以执行其他操作
else:
self.rinei_ma.append(self.closes[0])
self.rinei_mean = np.mean(self.rinei_ma)
# self.delta_cumsum=[]
# self.deltas_list=[]
# print('rinei_ma',self.rinei_ma)
clearing_executed = False
pass
return clearing_executed
run_kg = 每日重置数据()
# 过滤成交量为0或小于0
if self.data.volume[0] <= 0:
return
# print(f'volume,{self.data.volume[0]}')
if self.long_trailing_stop_price > 0 and self.pos > 0:
# print('datetime+sig: ',dt,'旧多头出线',self.long_trailing_stop_price,'low',self.low[0])
self.long_trailing_stop_price = (
self.low[0] if self.long_trailing_stop_price < self.low[0] else self.long_trailing_stop_price
)
# print('datetime+sig: ',dt,'多头出线',self.long_trailing_stop_price)
if self.short_trailing_stop_price > 0 and self.pos < 0:
# print('datetime+sig: ',dt,'旧空头出线',self.short_trailing_stop_price,'high',self.high[0])
self.short_trailing_stop_price = (
self.high[0] if self.high[0] < self.short_trailing_stop_price else self.short_trailing_stop_price
)
# print('datetime+sig: ',dt,'空头出线',self.short_trailing_stop_price)
self.out_long = self.long_trailing_stop_price * (1 - self.trailing_stop_percent)
self.out_short = self.short_trailing_stop_price * (1 + self.trailing_stop_percent)
# print('datetime+sig: ',dt,'空头出线',self.out_short)
# print('datetime+sig: ',dt,'多头出线',self.out_long)
# 跟踪出场
if self.out_long > 0:
if (
self.low[0] < self.out_long
and self.pos > 0
and self.sl_long_price > 0
and self.low[0] > self.sl_long_price
):
print(
"--多头止盈出场datetime+sig: ",
dt,
"Trailing stop triggered: Closing position",
"TR",
self.out_long,
"low",
self.low[0],
)
self.close(data=self.data, price=self.data.close[0], size=self.Lots, exectype=bt.Order.Market)
self.long_trailing_stop_price = 0
self.sl_long_price = 0
self.out_long = 0
self.pos = 0
if self.out_short > 0:
if (
self.high[0] > self.out_short
and self.pos < 0
and self.sl_shor_price > 0
and self.high[0] < self.sl_shor_price
):
print(
"--空头止盈出场datetime+sig: ",
dt,
"Trailing stop triggered: Closing position: ",
"TR",
self.out_short,
"high",
self.high[0],
)
self.close(data=self.data, price=self.data.close[0], size=self.Lots, exectype=bt.Order.Market)
self.short_trailing_stop_price = 0
self.sl_shor_price = 0
self.out_shor = 0
self.pos = 0
# 固定止损
self.fixed_stop_loss_L = self.sl_long_price * (1 - self.fixed_stop_loss_percent)
if (
self.sl_long_price > 0
and self.fixed_stop_loss_L > 0
and self.pos > 0
and self.closes[0] < self.fixed_stop_loss_L
):
print(
"--多头止损datetime+sig: ",
dt,
"Fixed stop loss triggered: Closing position",
"SL",
self.fixed_stop_loss_L,
"close",
self.closes[0],
)
self.close(data=self.data, price=self.data.close[0], size=self.Lots, exectype=bt.Order.Market)
self.long_trailing_stop_price = 0
self.sl_long_price = 0
self.out_long = 0
self.pos = 0
self.fixed_stop_loss_S = self.sl_shor_price * (1 + self.fixed_stop_loss_percent)
if (
self.sl_shor_price > 0
and self.fixed_stop_loss_S > 0
and self.pos < 0
and self.closes[0] > self.fixed_stop_loss_S
):
print(
"--空头止损datetime+sig: ",
dt,
"Fixed stop loss triggered: Closing position",
"SL",
self.fixed_stop_loss_S,
"close",
self.closes[0],
)
self.close(data=self.data, price=self.data.close[0], size=self.Lots, exectype=bt.Order.Market)
self.short_trailing_stop_price = 0
self.sl_shor_price = 0
self.out_short = 0
self.pos = 0
# 更新最高价和最低价的列表
self.datetime_list.append(dt)
self.high_list.append(self.data.high[0])
self.low_list.append(self.data.low[0])
self.close_list.append(self.data.close[0])
self.opens_list.append(self.data.open[0])
self.deltas_list.append(self.data.delta[0])
# 计算delta累计
self.delta_cumsum.append(sum(self.deltas_list))
# 将当前行数据添加到 DataFrame
# new_row = {
# 'datetime': dt,
# 'high': self.data.high[0],
# 'low': self.data.low[0],
# 'close': self.data.close[0],
# 'open': self.data.open[0],
# 'delta': self.data.delta[0],
# 'delta_cumsum': sum(self.deltas_list)
# }
# # 使用pandas.concat代替append
# self.df = pd.concat([self.df, pd.DataFrame([new_row])], ignore_index=True)
# # 检查文件是否存在
# csv_file_path = f"output.csv"
# if os.path.exists(csv_file_path):
# # 仅保存最后一行数据
# self.df.tail(1).to_csv(csv_file_path, mode='a', header=False, index=False)
# else:
# # 创建新文件并保存整个DataFrame
# self.df.to_csv(csv_file_path, index=False)
#
if run_kg == False: #
# ————jerome注释增加Boll函数测试
upper, middle, lower = tb.BBANDS(np.array(self.deltas_list), timeperiod=14, nbdevup=2, nbdevdn=2, matype=0)
upper_cum, middle_cum, lower_cum = tb.BBANDS(
np.array(self.delta_cumsum), timeperiod=14, nbdevup=2, nbdevdn=2, matype=0
)
# ————jerome注释增加Boll函数测试
# jerome注释self.signal[0] >1 1为堆积信号
# 开多组合= self.rinei_mean>0 and self.closes[0]>self.rinei_mean and self.signal[0] >1 and self.data.delta[0]>middle[-1] and self.delta_cumsum[-1]>middle_cum[-1]#jerome注释self.signal[0] >1 1为堆积信号and self.data.delta[0]>0 and self.delta_cumsum[-1]>2000
# 开空组合= self.rinei_mean>0 and self.closes[0]<self.rinei_mean and self.signal[0] <-1 and self.data.delta[0]<middle[-1] and self.delta_cumsum[-1]<middle_cum[-1]#jerome注释self.signal[0] >1 1为堆积信号and self.data.delta[0]<-0 and self.delta_cumsum[-1]<-2000
# 平多条件=self.pos<0 and self.signal[0] >1
# 平空条件=self.pos>0 and self.signal[0] <-1
开多组合 = (
self.rinei_mean > 0
and self.closes[0] > self.rinei_mean
and self.signal[0] > 2
and self.data.delta[0] > 600
and self.delta_cumsum[-1] > 200
) # jerome注释self.signal[0] >1 1为堆积信号and self.data.delta[0]>0 and self.delta_cumsum[-1]>2000
开空组合 = (
self.rinei_mean > 0
and self.closes[0] < self.rinei_mean
and self.signal[0] < -2
and self.data.delta[0] < -600
and self.delta_cumsum[-1] < -200
) # jerome注释self.signal[0] >1 1为堆积信号and self.data.delta[0]<-0 and self.delta_cumsum[-1]<-2000
平多条件 = self.pos < 0 and self.signal[0] > 2
平空条件 = self.pos > 0 and self.signal[0] < -2
if self.pos != 1: #
if 平多条件:
# print('datetime+sig: ', dt, 'Fixed stop loss triggered: Closing position', 'SL', self.fixed_stop_loss_S, 'close', self.closes[0])
self.close(data=self.data, price=self.data.close[0], exectype=bt.Order.Market)
self.short_trailing_stop_price = 0
self.sl_shor_price = 0
self.out_short = 0
self.pos = 0
if 开多组合: #
self.buy(data=self.data, price=self.data.close[0], size=1, exectype=bt.Order.Market)
self.pos = 1
self.long_trailing_stop_price = self.low[0]
self.sl_long_price = self.data.open[0]
# print('datetime+sig: ',dt,' sig: ',self.signal[0],'保存多头价格: ',self.long_trailing_stop_price)
if self.pos != -1: #
if 平空条件:
# print('datetime+sig: ', dt, 'Fixed stop loss triggered: Closing position', 'SL', self.fixed_stop_loss_L, 'close', self.closes[0])
self.close(data=self.data, price=self.data.close[0], exectype=bt.Order.Market)
self.long_trailing_stop_price = 0
self.sl_long_price = 0
self.out_long = 0
self.pos = 0
if 开空组合: #
self.sell(data=self.data, price=self.data.close[0], size=1, exectype=bt.Order.Market)
self.pos = -1
self.short_trailing_stop_price = self.high[0]
self.sl_shor_price = self.data.open[0]
# print('datetime+sig: ',dt,' sig: ',self.signal[0],'保存空头价格: ',self.short_trailing_stop_price)
if __name__ == "__main__":
# 创建Cerebro实例
cerebro = bt.Cerebro()
# 数据
csv_file = (
r"E:\of_data\主力连续\tick生成的OF数据(1M)\data_rs_merged\中金所\IM888\IM888_rs_2023_1T_back_ofdata_dj.csv"
)
png_filepath = r"E:\of_data\主力连续\tick生成的OF数据(1M)\data_rs_merged\中金所\IM888\部分回测报告"
# 从CSV文件加载数据
data = GenericCSV_SIG(
dataname=csv_file,
fromdate=datetime(2023, 1, 1),
todate=datetime(2023, 12, 29),
timeframe=bt.TimeFrame.Minutes,
nullvalue=0.0,
dtformat="%Y-%m-%d %H:%M:%S",
datetime=0,
high=3,
low=4,
open=2,
close=1,
volume=5,
openinterest=None,
sig=6,
delta=8,
)
# 添加数据到Cerebro实例
cerebro.adddata(data)
# 添加策略到Cerebro实例
cerebro.addstrategy(MyStrategy_固定止损_跟踪止盈)
# 添加观察者和分析器到Cerebro实例
# cerebro.addobserver(bt.observers.BuySell)
cerebro.addobserver(bt.observers.Value)
cerebro.addanalyzer(bt.analyzers.Returns, _name="returns")
cerebro.addanalyzer(bt.analyzers.DrawDown, _name="drawdown")
cerebro.addanalyzer(bt.analyzers.TradeAnalyzer, _name="trades")
初始资金 = 300000
cerebro.broker.setcash(初始资金) # 设置初始资金
# 手续费,单手保证金,合约倍数
cerebro.broker.setcommission(commission=30, margin=180000.0, mult=300) # 回测参数
# 运行回测
result = cerebro.run()
# 获取策略分析器中的结果
analyzer = result[0].analyzers
total_trades = analyzer.trades.get_analysis()["total"]["total"]
winning_trades = analyzer.trades.get_analysis()["won"]["total"]
# 获取TradeAnalyzer分析器的结果
trade_analyzer_result = analyzer.trades.get_analysis()
# 获取总收益额
total_profit = trade_analyzer_result.pnl.net.total
if total_trades > 0:
win_rate = winning_trades / total_trades
else:
win_rate = 0.0
# 打印回测报告
print("回测报告:")
print("期初权益", 初始资金)
print("期末权益", 初始资金 + round(total_profit))
print("盈亏额", round(total_profit))
print("最大回撤率,", round(analyzer.drawdown.get_analysis()["drawdown"], 2), "%")
print("胜率,", round(win_rate * 100, 2), "%")
print("交易次数,", total_trades)
print("盈利次数,", winning_trades)
print("亏损次数,", total_trades - winning_trades)
print("总手续费+滑点,", 手续费汇总)
手续费汇总 = 0
# 保存回测图像文件
plot = cerebro.plot()[0][0]
plot_filename = os.path.splitext(os.path.basename(csv_file))[0] + "ss" + "_plot.png"
# plot_path = os.path.join('部分回测报告', plot_filename)
if not os.path.exists(png_filepath):
# os.mkdir(png_filepath)
os.makedirs(png_filepath)
plot_path = os.path.join(png_filepath, plot_filename)
plot.savefig(plot_path)

View File

@@ -0,0 +1,523 @@
"""
以下是代码的详细说明:
#公众号松鼠Quant
#主页www.quant789.com
#本策略仅作学习交流使用,实盘交易盈亏投资者个人负责!!!
#版权归松鼠Quant所有禁止转发、转卖源码违者必究。
1.
导入必要的模块和库:
backtrader 用于回测功能
datetime 用于处理日期和时间
GenericCSVData 用于从CSV文件加载数据
numpy 用于数值操作
time 用于时间相关操作
matplotlib.pyplot 用于绘图
2. 定义自定义手续费模板MyCommission
继承自bt.CommInfoBase
3.
定义自定义数据源类 GenericCSV_SIG
继承自 GenericCSVData并添加了两个额外的行'sig''delta'
定义了参数 'sig''delta'
4.
定义 MyStrategy_固定止损_跟踪止盈 类:
继承自 bt.Strategybacktrader的基础策略类
定义了两个参数trailing_stop_percent 和 fixed_stop_loss_percent
初始化策略并设置各种变量和指标
实现了 next 方法该方法在数据源的每个新的K线出现时被调用
根据当前K线数据更新跟踪止盈价格
实现了跟踪止盈出场和固定止损出场
根据信号处理多头和空头仓位
在策略执行过程中打印调试信息
5.
if __name__ == "__main__": 代码块:
使用 Cerebro 实例设置回测环境
使用 GenericCSV_SIG 数据源从CSV文件加载数据
将数据源和策略添加到 Cerebro 实例中
添加观察者和分析器以评估性能
设置初始资金和经纪人参数
运行回测并获取结果
打印回测报告,包括收益率、回撤、胜率和交易统计数据
6.使用前事项:
1、主程序中修改ofdata_dj文件地址、png_filepath地址
2、修改clearing_time2_start、clearing_time2_stop
3、修改交易参数:lots、跟踪止损百分、固定止损百分比、duiji、cout_delta、delta
4、修改资金参数:初始资金;回测参数:回测时间段、佣金、单边保证金、手续费;
"""
import backtrader as bt
from datetime import datetime
from datetime import time as s_time
from backtrader.feeds import GenericCSVData
import numpy as np
import pandas as pd
import time
import matplotlib.pyplot as plt
import os
import talib as tb # jerom注释 增加talib库
手续费汇总 = 0
class GenericCSV_SIG(GenericCSVData):
# 从基类继承,添加一个 'sig'delta
lines = ("sig", "delta")
# 添加参数为从基类继承的参数
params = (("sig", 6), ("delta", 8))
class MyStrategy_固定止损_跟踪止盈(bt.Strategy):
params = (
("trailing_stop_percent", 0.005), # 跟踪止盈百分比
("fixed_stop_loss_percent", 0.01), # 固定止损百分比
)
def __init__(self):
self.Lots = 1 # 下单手数
self.signal = self.datas[0].sig # 使用sig字段作为策略的信号字段
self.delta = self.datas[0].delta
# 获取数据序列别名列表
line_aliases = self.datas[0].getlinealiases()
self.pos = 0
print(line_aliases)
self.high = self.datas[0].high
self.low = self.datas[0].low
self.closes = self.datas[0].close
self.open = self.datas[0].open
self.trailing_stop_percent = self.params.trailing_stop_percent
self.short_trailing_stop_price = 0
self.long_trailing_stop_price = 0
self.fixed_stop_loss_percent = self.params.fixed_stop_loss_percent
self.sl_long_price = 0
self.sl_shor_price = 0
self.out_long = 0
# 240884432
self.out_short = 0
self.rinei_ma = []
self.renei_high_ma = []
self.renei_low_ma = []
self.rinei_mean = 0
self.reniei_aroon_up = []
self.reniei_aroon_down = []
self.datetime_list = []
self.high_list = []
self.low_list = []
self.close_list = []
self.opens_list = []
self.deltas_list = []
self.delta_cumsum = []
self.barN = 0
self.df = pd.DataFrame(columns=["datetime", "high", "low", "close", "open", "delta", "delta_cumsum"])
self.trader_df = pd.DataFrame(columns=["open", "high", "low", "close", "volume", "openInterest", "delta"])
def log(self, txt, dt=None):
"""可选,构建策略打印日志的函数:可用于打印订单记录或交易记录等"""
dt = dt or self.datas[0].datetime.date(0)
print("%s, %s" % (dt.isoformat(), txt))
def notify_order(self, order):
# 未被处理的订单
if order.status in [order.Submitted, order.Accepted]:
return
# 已经处理的订单
if order.status in [order.Completed, order.Canceled, order.Margin]:
global 手续费汇总
if order.isbuy():
手续费汇总 += order.executed.comm
self.log(
"BUY EXECUTED, 订单编号:%.0f,成交价格: %.2f, 手续费滑点:%.2f, 成交量: %.2f, 品种: %s,手续费汇总:%.2f"
% (
order.ref, # 订单编号
order.executed.price, # 成交价
order.executed.comm, # 佣金
order.executed.size, # 成交量
order.data._name, # 品种名称
手续费汇总,
)
)
else: # Sell
手续费汇总 += order.executed.comm
self.log(
"SELL EXECUTED, 订单编号:%.0f,成交价格: %.2f, 手续费滑点:%.2f, 成交量: %.2f, 品种: %s,手续费汇总:%.2f"
% (
order.ref,
order.executed.price,
order.executed.comm,
order.executed.size,
order.data._name,
手续费汇总,
)
)
def next(self):
# 公众号松鼠Quant
# 主页www.quant789.com
# 本策略仅作学习交流使用,实盘交易盈亏投资者个人负责!!!
# 版权归松鼠Quant所有禁止转发、转卖源码违者必究。
# bar线计数初始化
self.barN += 1
position = self.getposition(self.datas[0]).size
# 时间轴
dt = bt.num2date(self.data.datetime[0])
# 更新跟踪止损价格
def 每日重置数据():
# 获取当前时间
current_time = dt.time()
# print(current_time)
# 设置清仓操作的时间范围114:55到15:00
clearing_time1_start = s_time(14, 55)
clearing_time1_end = s_time(15, 0)
# 设置清仓操作的时间范围200:55到01:00
clearing_time2_start = s_time(2, 25)
clearing_time2_end = s_time(2, 30)
# 创建一个标志变量
clearing_executed = False
if clearing_time1_start <= current_time <= clearing_time1_end and not clearing_executed:
clearing_executed = True # 设置标志变量为已执行
self.rinei_ma = []
self.renei_high_ma = []
self.renei_low_ma = []
self.delta_cumsum = []
self.deltas_list = []
elif clearing_time2_start <= current_time <= clearing_time2_end and not clearing_executed:
clearing_executed = True # 设置标志变量为已执行
self.rinei_ma = []
self.renei_high_ma = []
self.renei_low_ma = []
self.delta_cumsum = []
self.deltas_list = []
# 如果不在任何时间范围内,可以执行其他操作
else:
self.rinei_ma.append(self.closes[0])
self.renei_high_ma.append(self.high[0])
self.renei_low_ma.append(self.low[0])
self.rinei_mean = np.mean(self.rinei_ma)
self.reniei_aroon_up, self.reniei_aroon_down = tb.AROON(
np.array(self.renei_high_ma), np.array(self.renei_low_ma), 10
)
# self.delta_cumsum=[]
# self.deltas_list=[]
# print('rinei_ma',self.rinei_ma)
clearing_executed = False
pass
return clearing_executed
run_kg = 每日重置数据()
# 过滤成交量为0或小于0
if self.data.volume[0] <= 0:
return
# print(f'volume,{self.data.volume[0]}')
if self.long_trailing_stop_price > 0 and self.pos > 0:
# print('datetime+sig: ',dt,'旧多头出线',self.long_trailing_stop_price,'low',self.low[0])
self.long_trailing_stop_price = (
self.low[0] if self.long_trailing_stop_price < self.low[0] else self.long_trailing_stop_price
)
# print('datetime+sig: ',dt,'多头出线',self.long_trailing_stop_price)
if self.short_trailing_stop_price > 0 and self.pos < 0:
# print('datetime+sig: ',dt,'旧空头出线',self.short_trailing_stop_price,'high',self.high[0])
self.short_trailing_stop_price = (
self.high[0] if self.high[0] < self.short_trailing_stop_price else self.short_trailing_stop_price
)
# print('datetime+sig: ',dt,'空头出线',self.short_trailing_stop_price)
self.out_long = self.long_trailing_stop_price * (1 - self.trailing_stop_percent)
self.out_short = self.short_trailing_stop_price * (1 + self.trailing_stop_percent)
# print('datetime+sig: ',dt,'空头出线',self.out_short)
# print('datetime+sig: ',dt,'多头出线',self.out_long)
# 跟踪出场
if self.out_long > 0:
if (
self.low[0] < self.out_long
and self.pos > 0
and self.sl_long_price > 0
and self.low[0] > self.sl_long_price
):
print(
"--多头止盈出场datetime+sig: ",
dt,
"Trailing stop triggered: Closing position",
"TR",
self.out_long,
"low",
self.low[0],
)
self.close(data=self.data, price=self.data.close[0], size=self.Lots, exectype=bt.Order.Market)
self.long_trailing_stop_price = 0
self.sl_long_price = 0
self.out_long = 0
self.pos = 0
if self.out_short > 0:
if (
self.high[0] > self.out_short
and self.pos < 0
and self.sl_shor_price > 0
and self.high[0] < self.sl_shor_price
):
print(
"--空头止盈出场datetime+sig: ",
dt,
"Trailing stop triggered: Closing position: ",
"TR",
self.out_short,
"high",
self.high[0],
)
self.close(data=self.data, price=self.data.close[0], size=self.Lots, exectype=bt.Order.Market)
self.short_trailing_stop_price = 0
self.sl_shor_price = 0
self.out_shor = 0
self.pos = 0
# 固定止损
self.fixed_stop_loss_L = self.sl_long_price * (1 - self.fixed_stop_loss_percent)
if (
self.sl_long_price > 0
and self.fixed_stop_loss_L > 0
and self.pos > 0
and self.closes[0] < self.fixed_stop_loss_L
):
print(
"--多头止损datetime+sig: ",
dt,
"Fixed stop loss triggered: Closing position",
"SL",
self.fixed_stop_loss_L,
"close",
self.closes[0],
)
self.close(data=self.data, price=self.data.close[0], size=self.Lots, exectype=bt.Order.Market)
self.long_trailing_stop_price = 0
self.sl_long_price = 0
self.out_long = 0
self.pos = 0
self.fixed_stop_loss_S = self.sl_shor_price * (1 + self.fixed_stop_loss_percent)
if (
self.sl_shor_price > 0
and self.fixed_stop_loss_S > 0
and self.pos < 0
and self.closes[0] > self.fixed_stop_loss_S
):
print(
"--空头止损datetime+sig: ",
dt,
"Fixed stop loss triggered: Closing position",
"SL",
self.fixed_stop_loss_S,
"close",
self.closes[0],
)
self.close(data=self.data, price=self.data.close[0], size=self.Lots, exectype=bt.Order.Market)
self.short_trailing_stop_price = 0
self.sl_shor_price = 0
self.out_short = 0
self.pos = 0
# 更新最高价和最低价的列表
self.datetime_list.append(dt)
self.high_list.append(self.data.high[0])
self.low_list.append(self.data.low[0])
self.close_list.append(self.data.close[0])
self.opens_list.append(self.data.open[0])
self.deltas_list.append(self.data.delta[0])
# 计算delta累计
self.delta_cumsum.append(sum(self.deltas_list))
# 将当前行数据添加到 DataFrame
# new_row = {
# 'datetime': dt,
# 'high': self.data.high[0],
# 'low': self.data.low[0],
# 'close': self.data.close[0],
# 'open': self.data.open[0],
# 'delta': self.data.delta[0],
# 'delta_cumsum': sum(self.deltas_list)
# }
# # 使用pandas.concat代替append
# self.df = pd.concat([self.df, pd.DataFrame([new_row])], ignore_index=True)
# # 检查文件是否存在
# csv_file_path = f"output.csv"
# if os.path.exists(csv_file_path):
# # 仅保存最后一行数据
# self.df.tail(1).to_csv(csv_file_path, mode='a', header=False, index=False)
# else:
# # 创建新文件并保存整个DataFrame
# self.df.to_csv(csv_file_path, index=False)
#
if run_kg is False: #
# ————jerome注释增加Boll函数测试
upper, middle, lower = tb.BBANDS(np.array(self.deltas_list), timeperiod=5, nbdevup=2, nbdevdn=2, matype=0)
upper_cum, middle_cum, lower_cum = tb.BBANDS(
np.array(self.delta_cumsum), timeperiod=5, nbdevup=2, nbdevdn=2, matype=0
)
# ————jerome注释增加Boll函数测试
# jerome注释self.signal[0] >1 1为堆积信号
# 开多组合= self.rinei_mean>0 and self.closes[0]>self.rinei_mean and self.signal[0] >1 and self.data.delta[0]>middle[-1] and self.delta_cumsum[-1]>middle_cum[-1]#jerome注释self.signal[0] >1 1为堆积信号and self.data.delta[0]>0 and self.delta_cumsum[-1]>2000
# 开空组合= self.rinei_mean>0 and self.closes[0]<self.rinei_mean and self.signal[0] <-1 and self.data.delta[0]<middle[-1] and self.delta_cumsum[-1]<middle_cum[-1]#jerome注释self.signal[0] >1 1为堆积信号and self.data.delta[0]<-0 and self.delta_cumsum[-1]<-2000
开多组合 = (
self.reniei_aroon_up[-1] > 50
and self.reniei_aroon_up[-1] > self.reniei_aroon_down[-1]
# self.rinei_mean > 0
# and self.closes[0] > self.rinei_mean
and self.signal[0] > 2
and self.data.delta[0] > 500000
and self.delta_cumsum[-1] > 500000
)
开空组合 = (
self.reniei_aroon_down[-1] > 50
and self.reniei_aroon_up[-1] < self.reniei_aroon_down[-1]
# self.rinei_mean > 0
# and self.closes[0] < self.rinei_mean
and self.signal[0] < -2
and self.data.delta[0] < -500000
and self.delta_cumsum[-1] < -500000
)
平多条件 = self.pos < 0 and self.signal[0] > 2
平空条件 = self.pos > 0 and self.signal[0] < -2
if self.pos != 1: #
if 平多条件:
# print('datetime+sig: ', dt, 'Fixed stop loss triggered: Closing position', 'SL', self.fixed_stop_loss_S, 'close', self.closes[0])
self.close(data=self.data, price=self.data.close[0], exectype=bt.Order.Market)
self.short_trailing_stop_price = 0
self.sl_shor_price = 0
self.out_short = 0
self.pos = 0
if 开多组合: #
self.buy(data=self.data, price=self.data.close[0], size=1, exectype=bt.Order.Market)
self.pos = 1
self.long_trailing_stop_price = self.low[0]
self.sl_long_price = self.data.open[0]
# print('datetime+sig: ',dt,' sig: ',self.signal[0],'保存多头价格: ',self.long_trailing_stop_price)
if self.pos != -1: #
if 平空条件:
# print('datetime+sig: ', dt, 'Fixed stop loss triggered: Closing position', 'SL', self.fixed_stop_loss_L, 'close', self.closes[0])
self.close(data=self.data, price=self.data.close[0], exectype=bt.Order.Market)
self.long_trailing_stop_price = 0
self.sl_long_price = 0
self.out_long = 0
self.pos = 0
if 开空组合: #
self.sell(data=self.data, price=self.data.close[0], size=1, exectype=bt.Order.Market)
self.pos = -1
self.short_trailing_stop_price = self.high[0]
self.sl_shor_price = self.data.open[0]
# print('datetime+sig: ',dt,' sig: ',self.signal[0],'保存空头价格: ',self.short_trailing_stop_price)
if __name__ == "__main__":
# 公众号松鼠Quant
# 主页www.quant789.com
# 本策略仅作学习交流使用,实盘交易盈亏投资者个人负责!!!
# 版权归松鼠Quant所有禁止转发、转卖源码违者必究。
# 创建Cerebro实例
cerebro = bt.Cerebro()
# 数据
csv_file = r"D:\BaiduNetdiskDownload\主力连续\tick生成的OF数据(2M)\data_rs_merged\中金所\IM888\IM888_rs_2022_2T_back_ofdata_dj_new.csv"
png_filepath = r"D:\BaiduNetdiskDownload\主力连续\tick生成的OF数据(2M)\data_rs_merged\中金所\IM888\部分回测报告"
# 从CSV文件加载数据
data = GenericCSV_SIG(
dataname=csv_file,
fromdate=datetime(2022, 1, 1),
todate=datetime(2022, 12, 31),
timeframe=bt.TimeFrame.Minutes,
nullvalue=0.0,
dtformat="%Y-%m-%d %H:%M:%S",
datetime=0,
high=3,
low=4,
open=2,
close=1,
volume=5,
openinterest=None,
sig=6,
delta=8,
)
# 添加数据到Cerebro实例
cerebro.adddata(data)
# 添加策略到Cerebro实例
cerebro.addstrategy(MyStrategy_固定止损_跟踪止盈)
# 添加观察者和分析器到Cerebro实例
# cerebro.addobserver(bt.observers.BuySell)
cerebro.addobserver(bt.observers.Value)
cerebro.addanalyzer(bt.analyzers.Returns, _name="returns")
cerebro.addanalyzer(bt.analyzers.DrawDown, _name="drawdown")
cerebro.addanalyzer(bt.analyzers.TradeAnalyzer, _name="trades")
# cerebro.addanalyzer(bt.analyzers.sharpe, __name_= "sharpe")
初始资金 = 300000
cerebro.broker.setcash(初始资金) # 设置初始资金
# 手续费,单手保证金,合约倍数
cerebro.broker.setcommission(commission=14, margin=150000.0, mult=300) # 回测参数
# 运行回测
result = cerebro.run()
# 获取策略分析器中的结果
analyzer = result[0].analyzers
total_trades = analyzer.trades.get_analysis()["total"]["total"]
winning_trades = analyzer.trades.get_analysis()["won"]["total"]
# 获取TradeAnalyzer分析器的结果
trade_analyzer_result = analyzer.trades.get_analysis()
# 获取总收益额
total_profit = trade_analyzer_result.pnl.net.total
if total_trades > 0:
win_rate = winning_trades / total_trades
else:
win_rate = 0.0
# 打印回测报告
print("回测报告:")
print("期初权益", 初始资金)
print("期末权益", 初始资金 + round(total_profit))
print("盈亏额", round(total_profit))
print("最大回撤率,", round(analyzer.drawdown.get_analysis()["drawdown"], 2), "%")
print("胜率,", round(win_rate * 100, 2), "%")
print("交易次数,", total_trades)
print("盈利次数,", winning_trades)
print("亏损次数,", total_trades - winning_trades)
print("总手续费+滑点,", 手续费汇总)
手续费汇总 = 0
# 保存回测图像文件
plot = cerebro.plot()[0][0]
plot_filename = os.path.splitext(os.path.basename(csv_file))[0] + "ss" + "_plot.png"
# plot_path = os.path.join('部分回测报告', plot_filename)
if not os.path.exists(png_filepath):
# os.mkdir(png_filepath)
os.makedirs(png_filepath)
plot_path = os.path.join(png_filepath, plot_filename)
plot.savefig(plot_path)
# 公众号松鼠Quant
# 主页www.quant789.com
# 本策略仅作学习交流使用,实盘交易盈亏投资者个人负责!!!

View File

@@ -0,0 +1 @@
IF2023:combo: (0.008, 0.008, 5, 200, 200), value: 433379.9999999999, best_value: 563755.9999999976, best_parameters: (0.002, 0.004, 3, 0, 0)