双均线策略

定义

双均线策略

描述

策略逻辑

均线选择:

短期均线(快线):例如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; }
    }