双均线策略
双均线策略
定义
描述
策略逻辑
均线选择:
短期均线(快线):例如5日均线(MA5),反映短期价格趋势。
长期均线(慢线):例如20日均线(MA20),反映中长期趋势。
买卖信号:
买入信号:当短期均线 上穿 长期均线(金叉),且当前价格高于两条均线时,开仓做多。
卖出信号:当短期均线 下穿 长期均线(死叉),或价格跌破长期均线时,平仓止损。
过滤条件(可选):
加入成交量放大确认(避免假突破)。
限制交易时段(如避开财报发布期)。
均线选择:
短期均线(快线):例如5日均线(MA5),反映短期价格趋势。
长期均线(慢线):例如20日均线(MA20),反映中长期趋势。
买卖信号:
买入信号:当短期均线 上穿 长期均线(金叉),且当前价格高于两条均线时,开仓做多。
卖出信号:当短期均线 下穿 长期均线(死叉),或价格跌破长期均线时,平仓止损。
过滤条件(可选):
加入成交量放大确认(避免假突破)。
限制交易时段(如避开财报发布期)。
示例
/// <summary>
/// 双均线策略
/// </summary>
public class test : AlgorithmLogic
{
List<SymbloAvg> symbloAvgs = new List<SymbloAvg>();
/// <summary>
/// 基准
/// </summary>
private Symbol _Symbol;
public override void Initialize()
{
///系统设置 必须设置 因为此方法会获取策略ID 且必须是第一句
SetConfig(1, 5);
Print("初始化配置");
SetStartDate(BeginTime); // 设置回测开始日期
SetEndDate(EndTime); // 设置回测结束日期
Print("设置基准 300");
//设置基准 300
var index300 = AddIndex("000300.XSHG", Resolution.Minute);
SetBenchmark(index300);
SymbolPoolIndex.Add(index300);
//Print("放入指数池 上证380");
////放入指数池 上证380
//var index1000 = AddIndex("000009.XSHG", Resolution.Minute);
//SymbolPoolIndex.Add(index1000);
//Print("加载深证1000股票");
/////加载深证1000股票
FillStocks(["399011.XSHE"], (symbol) =>
{
symbol.FeeModel = new CustomFeeService();//手续费
symbol.SlippageModel = new SlippageModel(0.02m);//滑点
}, Resolution.Minute);
///设置数据预热
//SetWarmUp(TimeSpan.FromDays(30));
}
/// <summary>
/// 每天数据到达时调用
/// </summary>
/// <param name="slice"></param>
public override void OnData(Slice slice)
{
//预热的时间直接返回
if (IsWarmingUp) return;
//每日9.35取得当天需要的数据
if (Time.Hour == 9 && Time.Minute == 35)
{
Print($"每日9点35分获取当天数据 {Time}");
Console.WriteLine($"每日9点35分获取当天数据 {Time}");
var yesterday = GetCalendarDateTime(Time, false).Result;//上个交易日
var theDayBefore = GetCalendarDateTime(GetCalendarDateTime(Time, false).Result, false).Result;//上上个交易日
//取到所有股票的上个交易日和上上个交易日的日数据
List<Stock_price_history> theDayBeforeHistoryList = GetHistoryDay(theDayBefore, yesterday);
List<AvgModel> yesterAvg5 = new List<AvgModel>();
List<AvgModel> yesterAvg20 = new List<AvgModel>();
List<AvgModel> theDayBefore5 = new List<AvgModel>();
List<AvgModel> theDayBefore20 = new List<AvgModel>();
//第一天需要查询昨天和前天的均线,之后每天将昨天的均线作为前天的均线 GetAvgAll较慢减少每日调用的次数
if (symbloAvgs == null || symbloAvgs.Count == 0)
{
yesterAvg5 = GetAvgAll(5, Time);
yesterAvg20 = GetAvgAll(20, Time);
theDayBefore5 = GetAvgAll(5, yesterday);
theDayBefore20 = GetAvgAll(20, yesterday);
}
else
{
yesterAvg5 = GetAvgAll(5, Time);
yesterAvg20 = GetAvgAll(20, Time);
}
SymbolPool.ForEach(x =>
{
SymbloAvg symbloAvg = symbloAvgs.Find(y => y.code == x.Value);
//上一个交易日的历史数据
var yesterdayHistory = theDayBeforeHistoryList.FirstOrDefault(y => y.Date == yesterday.Date && y.Code == x.Value);
//上上个交易日的历史数据
var theDayBeforeHistory = theDayBeforeHistoryList.FirstOrDefault(y => y.Date == theDayBefore.Date && y.Code == x.Value);
if (symbloAvg == null)
{
symbloAvg = new SymbloAvg();
symbloAvg.code = x.Value;
symbloAvg.TodayAvg5 = yesterAvg5.FirstOrDefault(y => y.Symbol == x.Value)?.AvgPrice ?? 0m;
symbloAvg.TodayAvg20 = yesterAvg20.FirstOrDefault(y => y.Symbol == x.Value)?.AvgPrice ?? 0m;
symbloAvg.YesterdayAvg5 = theDayBefore5.FirstOrDefault(y => y.Symbol == x.Value)?.AvgPrice ?? 0m;
symbloAvg.YesterdayAvg20 = theDayBefore20.FirstOrDefault(y => y.Symbol == x.Value)?.AvgPrice ?? 0m;
symbloAvg.YesterdayVolume = yesterdayHistory?.Volume ?? 0m;
symbloAvg.TheDayBeforeVolume = theDayBeforeHistory?.Volume ?? 0m;
symbloAvgs.Add(symbloAvg);
}
else
{
symbloAvg.YesterdayAvg5 = symbloAvg.TodayAvg5;
symbloAvg.YesterdayAvg20 = symbloAvg.TodayAvg20;
symbloAvg.TodayAvg5 = yesterAvg5.FirstOrDefault(y => y.Symbol == x.Value)?.AvgPrice ?? 0m;
symbloAvg.TodayAvg20 = yesterAvg20.FirstOrDefault(y => y.Symbol == x.Value)?.AvgPrice ?? 0m;
symbloAvg.YesterdayVolume = yesterdayHistory?.Volume ?? 0m;
symbloAvg.TheDayBeforeVolume = theDayBeforeHistory?.Volume ?? 0m;
}
//Print($"股票:{symbloAvg.code},TodayAvg5:{symbloAvg.TodayAvg5},TodayAvg20:{symbloAvg.TodayAvg20},YesterdayAvg5:{symbloAvg.YesterdayAvg5},YesterdayAvg20:{symbloAvg.YesterdayAvg20},YesterdayVolume:{symbloAvg.YesterdayVolume},TheDayBeforeVolume:{symbloAvg.TheDayBeforeVolume}");
});
}
if (Time.Hour == 9 && Time.Minute == 40)
{
Print($"每日9点40分选股 {Time}");
//初始化每日选股池
SymbolPoolEveryDay = new List<string>();
if (Holdings.Count < 10)
{
Print($"持仓股票不满10支开始选股");
SymbolPool.ForEach(x =>
{
SymbloAvg symbloAvg = symbloAvgs.Find(y => y.code == x.Value);
if (symbloAvg != null)
{
if (symbloAvg.YesterdayAvg5 <= symbloAvg.YesterdayAvg20 && symbloAvg.TodayAvg5 > symbloAvg.TodayAvg20 && Securities[x].Price > symbloAvg.TodayAvg5 && Securities[x].Price > symbloAvg.TodayAvg20 && symbloAvg.YesterdayVolume > symbloAvg.TheDayBeforeVolume)
{
Print($"股票:{symbloAvg.code},TodayAvg5:{symbloAvg.TodayAvg5},TodayAvg20:{symbloAvg.TodayAvg20},YesterdayAvg5:{symbloAvg.YesterdayAvg5},YesterdayAvg20:{symbloAvg.YesterdayAvg20},YesterdayVolume:{symbloAvg.YesterdayVolume},TheDayBeforeVolume:{symbloAvg.TheDayBeforeVolume}");
//符合要求的选股
SymbolPoolEveryDay.Add(x.Value);
}
}
});
}
}
if (Time.Hour == 9 && Time.Minute == 41)
{
Print($"每日9点41分买入 {Time}");
Print($"选出股票: {SymbolPoolEveryDay.ToJson()}");
//判断是否满仓
//Print($"Holdings.Count: {Holdings.Count},SymbolPoolEveryDay.Count:{SymbolPoolEveryDay.Count}");
if (Holdings.Count < 10 && SymbolPoolEveryDay.Count > 0)
{
var buy = SymbolPoolEveryDay.Except(Holdings.Select(x => x.Symbol.Value).ToList()).Take(10 - Holdings.Count).ToList();
Print($"买入股票: {buy.ToJson()}");
if (buy.Count > 0)
{
var money = GetAvailableInvestmentCapital() / (10 - Holdings.Count); //每只股票平均分配资金
buy.ForEach(x =>
{
var tempSymbol = SymbolPool.Find(y => y.Value == x);
if (tempSymbol != null)
{
///这需要计算购买金额
Buy(tempSymbol, money, (status, msg, ticket) =>
{
if (status == 1)
{
//买入成功
Print($"买入股票:{x} 成功");
}
else
{
//买入失败
Print($"买入股票:{x} 失败,原因:{msg}");
}
});
}
});
}
}
}
if (Time.Hour == 9 && Time.Minute == 42)
{
Print($"每日9点42分卖出 {Time}");
if (Holdings.Count > 0)
{
Print($"Holdings {Holdings.ToJson()}");
var Holdings2 = Holdings.Select(x => x).ToList();
Holdings2.ForEach(x =>
{
SymbloAvg symbloAvg = symbloAvgs.Find(y => y.code == x.Symbol.Value);
if (symbloAvg != null)
{
if (symbloAvg.YesterdayAvg5 >= symbloAvg.YesterdayAvg20 && symbloAvg.TodayAvg5 < symbloAvg.TodayAvg20 && Securities[x.Symbol].Price < symbloAvg.TodayAvg20)
{
Print($"股票:{symbloAvg.code},TodayAvg5:{symbloAvg.TodayAvg5},TodayAvg20:{symbloAvg.TodayAvg20},YesterdayAvg5:{symbloAvg.YesterdayAvg5},YesterdayAvg20:{symbloAvg.YesterdayAvg20},YesterdayVolume:{symbloAvg.YesterdayVolume},TheDayBeforeVolume:{symbloAvg.TheDayBeforeVolume}");
//符合要求卖出
Print($"符合要求卖出股票: {x.Symbol}");
//卖出
Sell(x.Symbol, x.Quantity, (status, msg, ticket) =>
{
if (status == 3)
{
//卖出成功
Print($"卖出股票:{x.Symbol} 成功");
}
else
{
//卖出失败
Print($"卖出股票:{x.Symbol} 失败,原因:{msg}");
}
});
}
}
});
}
}
}
}
public class SymbloAvg
{
public string code { get; set; }
public decimal TodayAvg5 { get; set; }
public decimal TodayAvg20 { get; set; }
public decimal YesterdayAvg5 { get; set; }
public decimal YesterdayAvg20 { get; set; }
public decimal TheDayBeforeVolume { get; set; }
public decimal YesterdayVolume { get; set; }
}