Esempio n. 1
0
        protected override void CalcBar() {
            // 只在 Data2 有資料後才處理分線
            if (Data2.CurrentBar <= 1 || Bars.Info.Resolution.Type != EResolution.Minute) {
                return;
            }

            漲跌.Value = Bars.Close[0] - Bars.Open[0];
            漲跌幅.Value = 100 * ((Bars.Close[0] - Bars.Close[1]) / Bars.Close[1]);
            上影線.Value = Bars.High[0] - Math.Max(Bars.Open[0], Bars.Close[0]);
            下影線.Value = Math.Min(Bars.Open[0], Bars.Close[0]) - Bars.Low[0];
            實體線.Value = Math.Abs(Bars.Open[0] - Bars.Close[0]);
            成交日期 = int.Parse(Bars.Time[0].Date.ToString("yyyyMMdd"));
            成交時間 = int.Parse(Bars.BarUpdateTime.ToString("HHmmss"));
            string m_資料時間 = Bars.BarUpdateTime.ToString("HH:mm:ss");

            if (設定_啟用詳細訊息 && 設定_輸出集合 == null) {
                設定_輸出集合 = new Dictionary<string, string>();
                設定_輸出集合.Add("輸出記錄", "參數設定");
                設定_輸出集合.Add("策略名稱", 設定_策略名稱);
                設定_輸出集合.Add("策略版本", 設定_策略版本);
                #region 輸出指標策略參數
                設定_輸出集合.Add("作多參數", 作多參數.ToString());
                設定_輸出集合.Add("作空參數", 作空參數.ToString());
                設定_輸出集合.Add("作多天數", 作多天數.ToString());
                設定_輸出集合.Add("作空天數", 作空天數.ToString());
                設定_輸出集合.Add("啟用指標停損", 啟用指標停損.ToString());
                #endregion
                設定_輸出集合.Add("啟用順勢進場", 啟用順勢進場.ToString());
                設定_輸出集合.Add("順勢進場週間日", 順勢進場週間日);
                設定_輸出集合.Add("啟用逆勢進場", 啟用逆勢進場.ToString());
                設定_輸出集合.Add("逆勢進場週間日", 逆勢進場週間日);
                設定_輸出集合.Add("結算隔日進場月份", 結算隔日進場月份);
                設定_輸出集合.Add("資金_管理模式", 資金_管理模式.ToString());
                設定_輸出集合.Add("資金_風險比例", 資金_風險比例.ToString());
                設定_輸出集合.Add("資金_基本規模", 資金_基本規模.ToString());
                設定_輸出集合.Add("資金_跳空倍注", 資金_跳空倍注.ToString());
                設定_輸出集合.Add("資金_均多倍注", 資金_均多倍注.ToString());
                設定_輸出集合.Add("資金_均空倍注", 資金_均空倍注.ToString());
                設定_輸出集合.Add("資金_逆勢倍注", 資金_逆勢倍注.ToString());
                設定_輸出集合.Add("濾網_啟用多單", 濾網_啟用多單.ToString());
                設定_輸出集合.Add("濾網_啟用空單", 濾網_啟用空單.ToString());
                設定_輸出集合.Add("濾網_啟用當沖", 濾網_啟用當沖.ToString());
                設定_輸出集合.Add("濾網_開盤區間時間", 濾網_開盤區間時間.ToString());
                設定_輸出集合.Add("濾網_停單時間", 濾網_停單時間.ToString());
                設定_輸出集合.Add("加減碼_停損金額", 加減碼_停損金額.ToString());
                設定_輸出集合.Add("加減碼_停損點數", 停損點數.ToString());
                設定_輸出集合.Add("加減碼_加碼點數", 加減碼_加碼點數.ToString());
                設定_輸出集合.Add("加減碼_加碼次數", 加減碼_加碼次數.ToString());
                輸出詳細內容();
            }

            // 換日後需重算關鍵數值
            if (Bars.Time[0].Date > Bars.Time[1].Date && 重算日期 < 成交日期) {
                if (設定_啟用詳細訊息) {
                    設定_輸出集合.Clear();
                    設定_輸出集合.Add("輸出記錄", "新交易日");
                    設定_輸出集合.Add("原交易日", Bars.Time[1].Date.ToString("yyyy-MM-dd"));
                    設定_輸出集合.Add("新交易日", Bars.Time[0].Date.ToString("yyyy-MM-dd"));
                    設定_輸出集合.Add("資料時間", m_資料時間);
                    輸出詳細內容();
                }

                重算日期 = 0;
            }

            if (重算日期 == 0) {
                // 如非換日所引起的重算動作就跳出
                if (Bars.Time[0].Date < Bars.Time[1].Date) {
                    return;
                }

                昨最高 = Data2.High[0];
                昨最低 = Data2.Low[0];
                昨收盤 = Data2.Close[0];
                今開盤 = Bars.Open[0];
                開高價 = Bars.High[0];
                開低價 = Bars.Low[0];
                開收盤 = Bars.Close[0];
                開漲跌 = Bars.Open[0] - Data2.Close[0];
                開漲跌幅 = 100 * (開漲跌 / Data2.Close[0]);
                開盤區間高點 = 0;
                開盤區間低點 = int.MaxValue;
                ATR = AvgTrueRange.AverageTrueRange(this, 14, 0, 2);
                當日作多次數 = 0;
                當日作空次數 = 0;
                前次PositionSide = EMarketPositionSide.Flat;
                今最高 = Bars.High[0];
                今最低 = Bars.Low[0];
                今日停單 = false;
                週間日 = Bars.Time[0].DayOfWeek;

                // 資金管理:依模式計算下單規模
                double m_可用金額 = InitialCapital + NetProfit;
                double m_冒險金額 = m_可用金額 * 資金_風險比例;
                double m_市場風險 = 0;
                下單規模 = 資金_基本規模;

                switch (資金_管理模式) {
                    case 0: // 固定規模
                        下單規模 = 資金_基本規模;
                        break;
                    case 1: // 以保證金為基礎計算下單規模
                        m_市場風險 = Bars.Info.Margin;
                        下單規模 = Math.Max((int)Math.Floor(m_冒險金額 / m_市場風險), 資金_基本規模);
                        break;
                    case 2: // 以波動度為基礎計算下單規模
                        m_市場風險 = ATR * Bars.Info.BigPointValue;
                        下單規模 = Math.Max((int)Math.Floor(m_冒險金額 / m_市場風險), 資金_基本規模);
                        break;
                }

                if (資金_跳空倍注 > 0 && 開漲跌幅 >= 資金_跳空倍注) {
                    下單規模 *= 2;
                }

                if (資金_均多倍注 > 0 && 開收盤 > Data2.Close.Average(資金_均多倍注)) {
                    下單規模 *= 2;
                }

                if (資金_均空倍注 > 0 && 開收盤 < Data2.Close.Average(資金_均空倍注)) {
                    下單規模 *= 2;
                }

                #region 計算指標策略數值1
                // 原版 Dual Thrust 公式
                計算DualThrust(作多天數);
                作多區間 = 開收盤 + 作多參數 * Math.Max(m_HH - m_LC, m_HC - m_LL);
                計算DualThrust(作空天數);
                作空區間 = 開收盤 - 作空參數 * Math.Max(m_HH - m_LC, m_HC - m_LL);

                // 若 作多區間 - 作空區間 小於商品的 0.2% 幅度,今日就停單
                if (作多區間 - 作空區間 < 今開盤 * 0.002) {
                    今日停單 = true;
                }

                if (設定_啟用詳細訊息) {
                    設定_輸出集合.Clear();
                    設定_輸出集合.Add("輸出記錄", "指標數值");
                    設定_輸出集合.Add("時間", m_資料時間);
                    設定_輸出集合.Add("作多區間", 作多區間.ToString());
                    設定_輸出集合.Add("作空區間", 作空區間.ToString());
                    輸出詳細內容();
                }
                #endregion

                // 本交易日開倉,但不在進場月份中就停單
                if (結算日集合.ContainsKey(Bars.Time[1].Date) && !結算隔日進場月份集合[Bars.Time[0].Date.Month]) {
                    今日停單 = true;
                }

                if (設定_啟用詳細訊息 && 今日停單) {
                    設定_輸出集合.Clear();
                    設定_輸出集合.Add("輸出記錄", "今日停單");
                    設定_輸出集合.Add("日期", Bars.Time[0].ToString("yyyy-MM-dd"));
                    設定_輸出集合.Add("停單", 今日停單.ToString());
                    輸出詳細內容();
                }

                if (設定_啟用詳細訊息) {
                    設定_輸出集合.Clear();
                    設定_輸出集合.Add("輸出記錄", "下單規模");
                    設定_輸出集合.Add("口數", 下單規模.ToString());
                    輸出詳細內容();
                }

                重算日期 = 成交日期;
            }

            // 若仍無重算日期記錄就跳出
            if (重算日期 == 0) {
                return;
            }

            今最高 = Math.Max(今最高, Bars.High[0]);
            今最低 = Math.Min(今最低, Bars.Low[0]);

            #region 計算指標策略數值2

            #endregion

            // 開盤區間內只記錄高低價,不判斷訊號
            if (濾網_開盤區間時間 > 0 && 成交時間 <= 濾網_開盤區間時間) {
                開盤區間高點 = Math.Max(開盤區間高點, Bars.High[0]);
                開盤區間低點 = Math.Min(開盤區間低點, Bars.Low[0]);
                return;
            }

            if (CurrentPosition.Side == EMarketPositionSide.Long && 前次PositionSide == EMarketPositionSide.Flat) {
                當日作多次數++;
            }

            if (CurrentPosition.Side == EMarketPositionSide.Short && 前次PositionSide == EMarketPositionSide.Flat) {
                當日作空次數++;
            }

            // 判斷順勢進場新單訊號
            if (啟用順勢進場 == 1) {
                #region 順勢進場新單訊號
                if (CurrentPosition.Side == EMarketPositionSide.Flat && CurrentPosition.OpenTrades.Count == 0 && 成交時間 <= 濾網_停單時間 && !今日停單) {
                    if (濾網_啟用多單 == 1 && 當日作多次數 == 0 && Bars.Close[0] >= 作多區間 && 順勢進場週間日集合[週間日]) {
                        下單名稱 = "突破作多";

                        if (設定_啟用詳細訊息) {
                            下單名稱 = 設定_策略名稱 + "_" + 下單名稱;
                            設定_輸出集合.Clear();
                            設定_輸出集合.Add("輸出下單", 下單名稱);
                            設定_輸出集合.Add("時間", m_資料時間);
                            設定_輸出集合.Add("成交價", Bars.Close[0].ToString());
                            設定_輸出集合.Add("作多區間", 作多區間.ToString());
                            設定_輸出集合.Add("下單規模", 下單規模.ToString());
                            輸出詳細內容();
                        }

                        多單.Send(下單名稱, 下單規模);
                    }

                    if (濾網_啟用空單 == 1 && 當日作空次數 == 0 && Bars.Close[0] <= 作空區間 && 順勢進場週間日集合[週間日]) {
                        下單名稱 = "跌破作空";

                        if (設定_啟用詳細訊息) {
                            下單名稱 = 設定_策略名稱 + "_" + 下單名稱;
                            設定_輸出集合.Clear();
                            設定_輸出集合.Add("輸出下單", 下單名稱);
                            設定_輸出集合.Add("時間", m_資料時間);
                            設定_輸出集合.Add("成交價", Bars.Close[0].ToString());
                            設定_輸出集合.Add("作多區間", 作多區間.ToString());
                            設定_輸出集合.Add("下單規模", 下單規模.ToString());
                            輸出詳細內容();
                        }

                        空單.Send(下單名稱, 下單規模);
                    }
                }
                #endregion
            }

            // 判斷逆勢進場新單訊號
            if (啟用逆勢進場 == 1) {
                #region 逆勢進場新單訊號
                #endregion
            }

            // 判斷多單是否需要加碼
            if (CurrentPosition.Side == EMarketPositionSide.Long && CurrentPosition.OpenTrades.Count <= 加減碼_加碼次數) {
                if (Bars.Close[0] >= 最後進場部位.Price + 加減碼_加碼點數) {
                    下單名稱 = "多單加碼";

                    if (設定_啟用詳細訊息) {
                        下單名稱 = 設定_策略名稱 + "_" + 下單名稱;
                        設定_輸出集合.Clear();
                        設定_輸出集合.Add("輸出下單", 下單名稱);
                        設定_輸出集合.Add("時間", m_資料時間);
                        設定_輸出集合.Add("成交價", Bars.Close[0].ToString());
                        設定_輸出集合.Add("最後進場點位", 最後進場部位.Price.ToString());
                        設定_輸出集合.Add("加碼點位", (最後進場部位.Price + 加減碼_加碼點數).ToString());
                        設定_輸出集合.Add("下單規模", ((資金_逆勢倍注 == 1) ? 下單規模 * 2 : 下單規模).ToString());
                        輸出詳細內容();
                    }

                    多單.Send(下單名稱, 最後進場部位.Contracts);
                }
            }

            // 判斷空單是否需要加碼
            if (CurrentPosition.Side == EMarketPositionSide.Short && CurrentPosition.OpenTrades.Count <= 加減碼_加碼次數) {
                if (Bars.Close[0] <= 最後進場部位.Price - 加減碼_加碼點數) {
                    下單名稱 = "空單加碼";

                    if (設定_啟用詳細訊息) {
                        下單名稱 = 設定_策略名稱 + "_" + 下單名稱;
                        設定_輸出集合.Clear();
                        設定_輸出集合.Add("輸出下單", 下單名稱);
                        設定_輸出集合.Add("時間", m_資料時間);
                        設定_輸出集合.Add("成交價", Bars.Close[0].ToString());
                        設定_輸出集合.Add("最後進場點位", 最後進場部位.Price.ToString());
                        設定_輸出集合.Add("加碼點位", (最後進場部位.Price - 加減碼_加碼點數).ToString());
                        設定_輸出集合.Add("下單規模", ((資金_逆勢倍注 == 1) ? 下單規模 * 2 : 下單規模).ToString());
                        輸出詳細內容();
                    }

                    空單.Send(下單名稱, 最後進場部位.Contracts);
                }
            }

            // 判斷多單是否需要停損
            if (CurrentPosition.Side == EMarketPositionSide.Long && CurrentPosition.OpenTrades.Count > 0) {
                if (Bars.Close[0] <= 最後進場部位.Price - 停損點數) {
                    下單名稱 = "多單停損";

                    if (設定_啟用詳細訊息) {
                        下單名稱 = 設定_策略名稱 + "_" + 下單名稱;
                        設定_輸出集合.Clear();
                        設定_輸出集合.Add("輸出下單", 下單名稱 + "_虧損");
                        設定_輸出集合.Add("時間", m_資料時間);
                        設定_輸出集合.Add("成交價", Bars.Close[0].ToString());
                        設定_輸出集合.Add("最後進場點位", 最後進場部位.Price.ToString());
                        設定_輸出集合.Add("停損點位", (最後進場部位.Price - 停損點數).ToString());
                        輸出詳細內容();
                    }

                    多停.Send(下單名稱, 最後進場部位.Contracts);
                }

                #region 多單指標停損訊號
                if (啟用指標停損 == 1 && Bars.Close[0] <= 作空區間) {
                    下單名稱 = "多單停損";

                    if (設定_啟用詳細訊息) {
                        下單名稱 = 設定_策略名稱 + "_" + 下單名稱;
                        設定_輸出集合.Clear();
                        設定_輸出集合.Add("輸出下單", 下單名稱 + "_作空區間");
                        設定_輸出集合.Add("時間", m_資料時間);
                        設定_輸出集合.Add("成交價", Bars.Close[0].ToString());
                        設定_輸出集合.Add("最後進場點位", 最後進場部位.Price.ToString());
                        設定_輸出集合.Add("作空區間", 作空區間.ToString());
                        輸出詳細內容();
                    }

                    多停.Send(下單名稱, 最後進場部位.Contracts);
                }
                #endregion
            }

            // 判斷空單是否需要停損
            if (CurrentPosition.Side == EMarketPositionSide.Short && CurrentPosition.OpenTrades.Count > 0) {
                if (Bars.Close[0] >= 最後進場部位.Price + 停損點數) {
                    下單名稱 = "空單停損";

                    if (設定_啟用詳細訊息) {
                        下單名稱 = 設定_策略名稱 + "_" + 下單名稱;
                        設定_輸出集合.Clear();
                        設定_輸出集合.Add("輸出下單", 下單名稱 + "_虧損");
                        設定_輸出集合.Add("時間", m_資料時間);
                        設定_輸出集合.Add("成交價", Bars.Close[0].ToString());
                        設定_輸出集合.Add("最後進場點位", 最後進場部位.Price.ToString());
                        設定_輸出集合.Add("停損點位", (最後進場部位.Price + 停損點數).ToString());
                        輸出詳細內容();
                    }

                    空停.Send(下單名稱, 最後進場部位.Contracts);
                }

                #region 空單指標停損訊號
                if (啟用指標停損 == 1 && Bars.Close[0] >= 作多區間) {
                    下單名稱 = "空單停損";

                    if (設定_啟用詳細訊息) {
                        下單名稱 = 設定_策略名稱 + "_" + 下單名稱;
                        設定_輸出集合.Clear();
                        設定_輸出集合.Add("輸出下單", 下單名稱 + "_作多區間");
                        設定_輸出集合.Add("時間", m_資料時間);
                        設定_輸出集合.Add("成交價", Bars.Close[0].ToString());
                        設定_輸出集合.Add("最後進場點位", 最後進場部位.Price.ToString());
                        設定_輸出集合.Add("作多區間", 作多區間.ToString());
                        輸出詳細內容();
                    }

                    空停.Send(下單名稱, 最後進場部位.Contracts);
                }
                #endregion
            }

            // 當沖/隔日沖平倉
            if (CurrentPosition.Side != EMarketPositionSide.Flat && CurrentPosition.OpenTrades.Count > 0) {
                // 當沖時於指定出場時間全平
                if (濾網_啟用當沖 == 1 && 成交時間 >= 當沖出場時間) {
                    if (CurrentPosition.Side == EMarketPositionSide.Long) {
                        下單名稱 = "多單當沖全平";

                        if (設定_啟用詳細訊息) {
                            下單名稱 = 設定_策略名稱 + "_" + 下單名稱;
                            設定_輸出集合.Clear();
                            設定_輸出集合.Add("輸出下單", 下單名稱);
                            設定_輸出集合.Add("時間", m_資料時間);
                            設定_輸出集合.Add("成交價", Bars.Close[0].ToString());
                            設定_輸出集合.Add("下單規模", CurrentPosition.OpenLots.ToString());
                            輸出詳細內容();
                        }

                        多當沖.Send(下單名稱);
                    }

                    if (CurrentPosition.Side == EMarketPositionSide.Short) {
                        下單名稱 = "空單當沖全平";

                        if (設定_啟用詳細訊息) {
                            下單名稱 = 設定_策略名稱 + "_" + 下單名稱;
                            設定_輸出集合.Clear();
                            設定_輸出集合.Add("輸出下單", 下單名稱);
                            設定_輸出集合.Add("時間", m_資料時間);
                            設定_輸出集合.Add("成交價", Bars.Close[0].ToString());
                            設定_輸出集合.Add("下單規模", CurrentPosition.OpenLots.ToString());
                            輸出詳細內容();
                        }

                        空當沖.Send(下單名稱);
                    }
                } else {
                    // 結算當日強制於當沖出場時間平倉
                    if (結算日集合.ContainsKey(Bars.Time[0].Date) && 成交時間 >= 當沖出場時間) {
                        if (CurrentPosition.Side == EMarketPositionSide.Long) {
                            下單名稱 = "多單結算日全平";

                            if (設定_啟用詳細訊息) {
                                下單名稱 = 設定_策略名稱 + "_" + 下單名稱;
                                設定_輸出集合.Clear();
                                設定_輸出集合.Add("輸出下單", 下單名稱);
                                設定_輸出集合.Add("時間", m_資料時間);
                                設定_輸出集合.Add("成交價", Bars.Close[0].ToString());
                                設定_輸出集合.Add("下單規模", CurrentPosition.OpenLots.ToString());
                                輸出詳細內容();
                            }

                            多當沖.Send(下單名稱);
                        }

                        if (CurrentPosition.Side == EMarketPositionSide.Short) {
                            下單名稱 = "空單結算日全平";

                            if (設定_啟用詳細訊息) {
                                下單名稱 = 設定_策略名稱 + "_" + 下單名稱;
                                設定_輸出集合.Clear();
                                設定_輸出集合.Add("輸出下單", 下單名稱);
                                設定_輸出集合.Add("時間", m_資料時間);
                                設定_輸出集合.Add("成交價", Bars.Close[0].ToString());
                                設定_輸出集合.Add("下單規模", CurrentPosition.OpenLots.ToString());
                                輸出詳細內容();
                            }

                            空當沖.Send(下單名稱);
                        }
                    }

                    // 隔日沖時於隔日開盤市價平倉
                    if (!結算日集合.ContainsKey(Bars.Time[0].Date) && 成交時間 >= 濾網_停單時間) {
                        if (CurrentPosition.Side == EMarketPositionSide.Long) {
                            下單名稱 = "多單隔日沖全平";

                            if (設定_啟用詳細訊息) {
                                下單名稱 = 設定_策略名稱 + "_" + 下單名稱;
                                設定_輸出集合.Clear();
                                設定_輸出集合.Add("輸出下單", 下單名稱);
                                設定_輸出集合.Add("時間", m_資料時間);
                                設定_輸出集合.Add("成交價", Bars.Close[0].ToString());
                                設定_輸出集合.Add("下單規模", CurrentPosition.OpenLots.ToString());
                                輸出詳細內容();
                            }

                            多隔沖.Send(下單名稱);
                        }

                        if (CurrentPosition.Side == EMarketPositionSide.Short) {
                            下單名稱 = "空單隔日沖全平";

                            if (設定_啟用詳細訊息) {
                                下單名稱 = 設定_策略名稱 + "_" + 下單名稱;
                                設定_輸出集合.Clear();
                                設定_輸出集合.Add("輸出下單", 下單名稱);
                                設定_輸出集合.Add("時間", m_資料時間);
                                設定_輸出集合.Add("成交價", Bars.Close[0].ToString());
                                設定_輸出集合.Add("下單規模", CurrentPosition.OpenLots.ToString());
                                輸出詳細內容();
                            }

                            空隔沖.Send(下單名稱);
                        }
                    }
                }
            }

            前次PositionSide = CurrentPosition.Side;
        }
Esempio n. 2
0
        protected override void StartCalc() {
            Data2 = BarsOfData(2);
            當沖出場時間 = 132955;
            前次PositionSide = EMarketPositionSide.Flat;

            // 啟用當沖時,若停單時間比 13:30 晚,就提前至 13:30
            if (濾網_啟用當沖 == 1) {
                濾網_停單時間 = Math.Min(濾網_停單時間, 當沖出場時間);
            }

            // 建立結算日資料集合,結算當日強制於當沖出場時間平倉
            string 結算日檔案路徑 = 設定_資料檔目錄 + "ExpireDate.TW.csv";
            結算日集合.Clear();
            if (File.Exists(結算日檔案路徑)) {
                string[] 結算日陣列 = File.ReadAllLines(結算日檔案路徑);
                for (int i = 0; i < 結算日陣列.Length; i++) {
                    結算日集合.Add(DateTime.ParseExact(結算日陣列[i], "yyyy/MM/dd", CultureInfo.InvariantCulture), true);
                }
            }

            // 建立順勢/逆勢進場週間日集合,只有允許週間日才能進場
            順勢進場週間日集合.Clear();
            逆勢進場週間日集合.Clear();
            string[] 順勢進場週間日陣列 = 順勢進場週間日.Split(new char[] { ',' });
            string[] 逆勢進場週間日陣列 = 逆勢進場週間日.Split(new char[] { ',' });

            for (int i = 0; i <= 6; i++) {
                bool 啟用 = 順勢進場週間日陣列.Count(x => x == i.ToString()) > 0;
                順勢進場週間日集合.Add((DayOfWeek)i, 啟用);

                啟用 = 逆勢進場週間日陣列.Count(x => x == i.ToString()) > 0;
                逆勢進場週間日集合.Add((DayOfWeek)i, 啟用);
            }

            // 建立結算隔日進場集合,只有允許月份才能進場
            結算隔日進場月份集合.Clear();
            string[] 結算隔日進場月份陣列 = 結算隔日進場月份.Split(new char[] { ',' });

            for (int i = 1; i <= 12; i++) {
                bool 啟用 = 結算隔日進場月份陣列.Count(x => x == i.ToString()) > 0;
                結算隔日進場月份集合.Add(i, 啟用);
            }

            // 計算停損金額在不同商品間換算出的停損點數,如 $3,000 在台指期的停損點數為 15 點
            double 每跳動點價值 = Bars.Info.MinMove / Bars.Info.PriceScale * Bars.Info.BigPointValue;
            if (加減碼_停損金額 > 0) {
                停損點數 = 加減碼_停損金額 / 每跳動點價值;
            }

            if (加減碼_停損金額 == -1) { //預設15點
                停損點數 = 15;  // 固定15點
                加減碼_停損金額 = (int)(停損點數 * 每跳動點價值);
            }

            設定_輸出集合 = null;
            重算日期 = 0;
        }
        protected override void CalcBar() {
            // 只在 Data2 有資料後才處理分線
            if (Data2.CurrentBar <= 1 || Bars.Info.Resolution.Type != EResolution.Minute) {
                return;
            }

            漲跌.Value = Bars.Close[0] - Bars.Open[0];
            漲跌幅.Value = 100 * ((Bars.Close[0] - Bars.Close[1]) / Bars.Close[1]);
            上影線.Value = Bars.High[0] - Math.Max(Bars.Open[0], Bars.Close[0]);
            下影線.Value = Math.Min(Bars.Open[0], Bars.Close[0]) - Bars.Low[0];
            實體線.Value = Math.Abs(Bars.Open[0] - Bars.Close[0]);
            成交日期 = int.Parse(Bars.Time[0].Date.ToString("yyyyMMdd"));
            成交時間 = int.Parse(Bars.BarUpdateTime.ToString("HHmmss"));
            string m_資料時間 = Bars.BarUpdateTime.ToString("HH:mm:ss");

            if (設定_啟用詳細訊息 && 設定_輸出集合 == null) {
                設定_輸出集合 = new Dictionary<string, string>();
                設定_輸出集合.Add("輸出記錄", "參數設定");
                設定_輸出集合.Add("策略名稱", 設定_策略名稱);
                設定_輸出集合.Add("策略版本", 設定_策略版本);
                #region 輸出指標策略參數
                設定_輸出集合.Add("開始交易時間", 開始交易時間.ToString());
                設定_輸出集合.Add("結束交易時間", 結束交易時間.ToString());
                設定_輸出集合.Add("今日交易獲利次數", 今日交易獲利次數.ToString());
                設定_輸出集合.Add("今日交易連續虧損最多次數", 今日交易連續虧損最多次數.ToString());
                設定_輸出集合.Add("期初狀態", 期初狀態.ToString());

                設定_輸出集合.Add("交易多空1", 交易多空1.ToString());
                設定_輸出集合.Add("間隔秒數1", 間隔秒數1.ToString());
                設定_輸出集合.Add("自設停利點數1", 自設停利點數1.ToString());
                設定_輸出集合.Add("自設停損點數1", 自設停損點數1.ToString());
                設定_輸出集合.Add("下單口數1", 下單口數1.ToString());

                設定_輸出集合.Add("交易多空2", 交易多空2.ToString());
                設定_輸出集合.Add("間隔秒數2", 間隔秒數2.ToString());
                設定_輸出集合.Add("自設停利點數2", 自設停利點數2.ToString());
                設定_輸出集合.Add("自設停損點數2", 自設停損點數2.ToString());
                設定_輸出集合.Add("下單口數2", 下單口數2.ToString());

                設定_輸出集合.Add("交易多空3", 交易多空3.ToString());
                設定_輸出集合.Add("間隔秒數3", 間隔秒數3.ToString());
                設定_輸出集合.Add("自設停利點數3", 自設停利點數3.ToString());
                設定_輸出集合.Add("自設停損點數3", 自設停損點數3.ToString());
                設定_輸出集合.Add("下單口數3", 下單口數3.ToString());

                設定_輸出集合.Add("交易多空4", 交易多空4.ToString());
                設定_輸出集合.Add("間隔秒數4", 間隔秒數4.ToString());
                設定_輸出集合.Add("自設停利點數4", 自設停利點數4.ToString());
                設定_輸出集合.Add("自設停損點數4", 自設停損點數4.ToString());
                設定_輸出集合.Add("下單口數4", 下單口數4.ToString());
                #endregion
                輸出詳細內容();
            }

            // 換日後需重算關鍵數值
            if (Bars.Time[0].Date > Bars.Time[1].Date && 重算日期 < 成交日期) {
                if (設定_啟用詳細訊息) {
                    設定_輸出集合.Clear();
                    設定_輸出集合.Add("輸出記錄", "新交易日");
                    設定_輸出集合.Add("原交易日", Bars.Time[1].Date.ToString("yyyy-MM-dd"));
                    設定_輸出集合.Add("新交易日", Bars.Time[0].Date.ToString("yyyy-MM-dd"));
                    設定_輸出集合.Add("資料時間", m_資料時間);
                    輸出詳細內容();
                }

                重算日期 = 0;
            }

            if (重算日期 == 0) {
                // 如非換日所引起的重算動作就跳出
                if (Bars.Time[0].Date < Bars.Time[1].Date) {
                    return;
                }

                昨最高 = Data2.High[0];
                昨最低 = Data2.Low[0];
                昨收盤 = Data2.Close[0];
                今開盤 = Bars.Open[0];
                開高價 = Bars.High[0];
                開低價 = Bars.Low[0];
                開收盤 = Bars.Close[0];
                開漲跌 = Bars.Open[0] - Data2.Close[0];
                開漲跌幅 = 100 * (開漲跌 / Data2.Close[0]);
                開盤區間高點 = 0;
                開盤區間低點 = int.MaxValue;
                ATR = AvgTrueRange.AverageTrueRange(this, 14, 0, 2);
                當日作多次數 = 0;
                當日作空次數 = 0;
                前次PositionSide = EMarketPositionSide.Flat;
                今最高 = Bars.High[0];
                今最低 = Bars.Low[0];
                今日停單 = false;
                週間日 = Bars.Time[0].DayOfWeek;
                // 資金管理:依模式計算下單規模
                double m_可用金額 = InitialCapital + NetProfit;
                double m_冒險金額 = m_可用金額 * 資金_風險比例;
                #region 計算指標策略數值1
                單次下單次數 = 期初狀態; //換日需重算,需在此填入初始值
                今日成功交易次數 = 0;//換日需重算
                #endregion



                重算日期 = 成交日期;
            }

            // 若仍無重算日期記錄就跳出
            if (重算日期 == 0) {
                return;
            }

            今最高 = Math.Max(今最高, Bars.High[0]);
            今最低 = Math.Min(今最低, Bars.Low[0]);

            #region 計算指標策略數值2

            #endregion



            if (CurrentPosition.Side == EMarketPositionSide.Long && 前次PositionSide == EMarketPositionSide.Flat) {
                
                if (設定_啟用詳細訊息) {
                    設定_輸出集合.Clear();
                    設定_輸出集合.Add("輸出下單", 設定_策略名稱 + "_狀態");
                    設定_輸出集合.Add("目前狀態", string.Format("失敗:{0} /成功:{1}", 單次下單次數, 今日成功交易次數));
                    輸出詳細內容();
                }
                單次下單次數++;
            }

            if (CurrentPosition.Side == EMarketPositionSide.Short && 前次PositionSide == EMarketPositionSide.Flat) {
               
                if (設定_啟用詳細訊息) {
                    設定_輸出集合.Clear();
                    設定_輸出集合.Add("輸出下單", 設定_策略名稱 + "_狀態");
                    設定_輸出集合.Add("目前狀態", string.Format("失敗:{0} /成功:{1}", 單次下單次數, 今日成功交易次數));
                    輸出詳細內容();
                }
                單次下單次數++;
            }

            if (CurrentPosition.Side == EMarketPositionSide.Flat && 前次PositionSide == EMarketPositionSide.Long) {
                上筆成交時間 = int.Parse(Bars.BarUpdateTime.ToString("HHmmss"));
                if (Is多單獲利) {
                    Is多單獲利 = false;
                    當日作多次數++;
                    今日成功交易次數++;
                    單次下單次數 = 0; //停利重頭開始後繼續玩
                    if (今日成功交易次數 >= 今日交易獲利次數) {
                        // 獲利了結今日停單
                        今日停單 = true;

                        if (設定_啟用詳細訊息) {
                            下單名稱 = 設定_策略名稱 + "_" + 下單名稱;
                            設定_輸出集合.Clear();
                            設定_輸出集合.Add("輸出下單", 下單名稱 + "_停單");
                            設定_輸出集合.Add("已達今日成功交易次數", 今日成功交易次數.ToString());
                            設定_輸出集合.Add("目前狀態", string.Format("失敗:{0} /成功:{1}", 單次下單次數, 今日成功交易次數));
                            輸出詳細內容();
                        }
                    }
                }
            }
            if (CurrentPosition.Side == EMarketPositionSide.Flat && 前次PositionSide == EMarketPositionSide.Short) {
                上筆成交時間 = int.Parse(Bars.BarUpdateTime.ToString("HHmmss"));
                if (Is空單獲利) {
                    Is空單獲利 = false;
                    當日作空次數++;
                    今日成功交易次數++;
                    單次下單次數 = 0; //停利重頭開始後繼續玩
                    if (今日成功交易次數 >= 今日交易獲利次數) {
                        // 獲利了結今日停單
                        今日停單 = true;

                        if (設定_啟用詳細訊息) {
                            設定_輸出集合.Clear();
                            設定_輸出集合.Add("輸出下單", 設定_策略名稱 + "_停單");
                            設定_輸出集合.Add("已達今日成功交易次數", 今日成功交易次數.ToString());
                            設定_輸出集合.Add("目前狀態", string.Format("失敗:{0} /成功:{1}", 單次下單次數, 今日成功交易次數));
                            輸出詳細內容();
                        }
                    }
                }
            }

            //--- 下單  ---//
            if (成交時間 <= 結束交易時間 && CurrentPosition.Side == EMarketPositionSide.Flat && CurrentPosition.OpenTrades.Count == 0 && !今日停單) {

                //第一次 時間到多單進場
                switch (單次下單次數) {
                    case 0:
                        int rt0 = CalDelay((上筆成交時間 == 0) ? 開始交易時間 : 上筆成交時間, 間隔秒數1);
                        if (成交時間 >=rt0) {
                            if (交易多空1 == 1) {
                                下單名稱 = "做多1";
                                多單.Send(下單名稱, 下單口數1);
                            } else {
                                下單名稱 = "做空1";
                                空單.Send(下單名稱, 下單口數1);
                            }
                        }
                        break;
                    case 1:
                        int rt1 = CalDelay(上筆成交時間, 間隔秒數2);
                        if (成交時間 >= rt1) {
                            if (交易多空2 == 1) {
                                下單名稱 = "做多2";
                                多單.Send(下單名稱, 下單口數2);
                            } else {
                                下單名稱 = "做空2";
                                空單.Send(下單名稱, 下單口數2);
                            }
                        }
                        break;
                    case 2:
                        int rt2 = CalDelay(上筆成交時間, 間隔秒數3);
                        if (成交時間 >= rt2) {
                            if (交易多空3 == 1) {
                                下單名稱 = "做多3";
                                多單.Send(下單名稱, 下單口數3);
                            } else {
                                下單名稱 = "做空3";
                                空單.Send(下單名稱, 下單口數3);
                            }
                        }
                        break;
                    case 3:
                        int rt3 = CalDelay(上筆成交時間, 間隔秒數4);
                        if (成交時間 >= rt3) {
                            if (交易多空4 == 1) {
                                下單名稱 = "做多4";
                                多單.Send(下單名稱, 下單口數4);
                            } else {
                                下單名稱 = "做空4";
                                空單.Send(下單名稱, 下單口數4);
                            }
                        }
                        break;
                    default:
                        break;
                }

                if (今日交易連續虧損最多次數 <= 單次下單次數) { // 已達連續虧損次數立即停單
                    今日停單 = true;

                    if (設定_啟用詳細訊息) {
                        設定_輸出集合.Clear();
                        設定_輸出集合.Add("輸出下單", 設定_策略名稱 + "_停單");
                        設定_輸出集合.Add("已達連續虧損次數", 今日交易連續虧損最多次數.ToString());
                        設定_輸出集合.Add("目前狀態", string.Format("失敗:{0} /成功:{1}", 單次下單次數, 今日成功交易次數));
                        輸出詳細內容();
                    }
                }
            }



            //--- 平倉 ---//
            if (CurrentPosition.OpenTrades.Count > 0) {
                int i停利點數 = 0, i停損點數 = 0;
                switch (單次下單次數) {
                    case 1:
                        i停利點數 = 自設停利點數1;
                        i停損點數 = 自設停損點數1;
                        break;
                    case 2:
                        i停利點數 = 自設停利點數2;
                        i停損點數 = 自設停損點數2;
                        break;
                    case 3:
                        i停利點數 = 自設停利點數3;
                        i停損點數 = 自設停損點數3;
                        break;
                    case 4:
                        i停利點數 = 自設停利點數4;
                        i停損點數 = 自設停損點數4;
                        break;
                    default:
                        break;
                }
                // 判斷多單是否需要停損
                if (CurrentPosition.Side == EMarketPositionSide.Long) {

                    if (Bars.Close[0] >= 最後進場部位.Price + i停利點數) {
                        下單名稱 = "多單停利";

                        if (設定_啟用詳細訊息) {
                            下單名稱 = 設定_策略名稱 + "_" + 下單名稱;
                            設定_輸出集合.Clear();
                            設定_輸出集合.Add("輸出下單", 下單名稱 + "_獲利");
                            設定_輸出集合.Add("時間", m_資料時間);
                            設定_輸出集合.Add("成交價", Bars.Close[0].ToString());
                            設定_輸出集合.Add("最後進場點位", 最後進場部位.Price.ToString());
                            設定_輸出集合.Add("自設停利點數", (最後進場部位.Price + i停利點數).ToString());
                            輸出詳細內容();
                        }

                        多停.Send(下單名稱);

                        Is多單獲利 = true;

                    }

                    if (Bars.Close[0] <= 最後進場部位.Price - i停損點數) {
                        下單名稱 = "多單停損";

                        if (設定_啟用詳細訊息) {
                            下單名稱 = 設定_策略名稱 + "_" + 下單名稱;
                            設定_輸出集合.Clear();
                            設定_輸出集合.Add("輸出下單", 下單名稱 + "_虧損");
                            設定_輸出集合.Add("時間", m_資料時間);
                            設定_輸出集合.Add("成交價", Bars.Close[0].ToString());
                            設定_輸出集合.Add("最後進場點位", 最後進場部位.Price.ToString());
                            設定_輸出集合.Add("自設停損點數", (最後進場部位.Price - i停損點數).ToString());
                            輸出詳細內容();
                        }

                        多停.Send(下單名稱);
                    }

                }

                // 判斷空單是否需要停損
                if (CurrentPosition.Side == EMarketPositionSide.Short) {
                    if (Bars.Close[0] <= 最後進場部位.Price - i停利點數) {
                        下單名稱 = "空單停利";

                        if (設定_啟用詳細訊息) {
                            下單名稱 = 設定_策略名稱 + "_" + 下單名稱;
                            設定_輸出集合.Clear();
                            設定_輸出集合.Add("輸出下單", 下單名稱 + "_獲利");
                            設定_輸出集合.Add("時間", m_資料時間);
                            設定_輸出集合.Add("成交價", Bars.Close[0].ToString());
                            設定_輸出集合.Add("最後進場點位", 最後進場部位.Price.ToString());
                            設定_輸出集合.Add("停利點位", (最後進場部位.Price - i停利點數).ToString());
                            輸出詳細內容();
                        }

                        空停.Send(下單名稱);

                        Is空單獲利 = true;
                    }
                    if (Bars.Close[0] >= 最後進場部位.Price + i停損點數) {
                        下單名稱 = "空單停損";

                        if (設定_啟用詳細訊息) {
                            下單名稱 = 設定_策略名稱 + "_" + 下單名稱;
                            設定_輸出集合.Clear();
                            設定_輸出集合.Add("輸出下單", 下單名稱 + "_虧損");
                            設定_輸出集合.Add("時間", m_資料時間);
                            設定_輸出集合.Add("成交價", Bars.Close[0].ToString());
                            設定_輸出集合.Add("最後進場點位", 最後進場部位.Price.ToString());
                            設定_輸出集合.Add("停損點位", (最後進場部位.Price + i停損點數).ToString());
                            輸出詳細內容();
                        }

                        空停.Send(下單名稱);
                    }

                }

            }

            // 當沖/隔日沖平倉
            if (CurrentPosition.Side != EMarketPositionSide.Flat && CurrentPosition.OpenTrades.Count > 0) {
                // 當沖時於指定出場時間全平
                if (濾網_啟用當沖 == 1 && 成交時間 >= 當沖出場時間) {
                    if (CurrentPosition.Side == EMarketPositionSide.Long) {
                        下單名稱 = "多單當沖全平";

                        if (設定_啟用詳細訊息) {
                            下單名稱 = 設定_策略名稱 + "_" + 下單名稱;
                            設定_輸出集合.Clear();
                            設定_輸出集合.Add("輸出下單", 下單名稱);
                            設定_輸出集合.Add("時間", m_資料時間);
                            設定_輸出集合.Add("成交價", Bars.Close[0].ToString());
                            設定_輸出集合.Add("下單規模", CurrentPosition.OpenLots.ToString());
                            輸出詳細內容();
                        }

                        多當沖.Send(下單名稱);
                    }

                    if (CurrentPosition.Side == EMarketPositionSide.Short) {
                        下單名稱 = "空單當沖全平";

                        if (設定_啟用詳細訊息) {
                            下單名稱 = 設定_策略名稱 + "_" + 下單名稱;
                            設定_輸出集合.Clear();
                            設定_輸出集合.Add("輸出下單", 下單名稱);
                            設定_輸出集合.Add("時間", m_資料時間);
                            設定_輸出集合.Add("成交價", Bars.Close[0].ToString());
                            設定_輸出集合.Add("下單規模", CurrentPosition.OpenLots.ToString());
                            輸出詳細內容();
                        }

                        空當沖.Send(下單名稱);
                    }
                } else {
                    // 結算當日強制於當沖出場時間平倉
                    if (結算日集合.ContainsKey(Bars.Time[0].Date) && 成交時間 >= 當沖出場時間) {
                        if (CurrentPosition.Side == EMarketPositionSide.Long) {
                            下單名稱 = "多單結算日全平";

                            if (設定_啟用詳細訊息) {
                                下單名稱 = 設定_策略名稱 + "_" + 下單名稱;
                                設定_輸出集合.Clear();
                                設定_輸出集合.Add("輸出下單", 下單名稱);
                                設定_輸出集合.Add("時間", m_資料時間);
                                設定_輸出集合.Add("成交價", Bars.Close[0].ToString());
                                設定_輸出集合.Add("下單規模", CurrentPosition.OpenLots.ToString());
                                輸出詳細內容();
                            }

                            多當沖.Send(下單名稱);
                        }

                        if (CurrentPosition.Side == EMarketPositionSide.Short) {
                            下單名稱 = "空單結算日全平";

                            if (設定_啟用詳細訊息) {
                                下單名稱 = 設定_策略名稱 + "_" + 下單名稱;
                                設定_輸出集合.Clear();
                                設定_輸出集合.Add("輸出下單", 下單名稱);
                                設定_輸出集合.Add("時間", m_資料時間);
                                設定_輸出集合.Add("成交價", Bars.Close[0].ToString());
                                設定_輸出集合.Add("下單規模", CurrentPosition.OpenLots.ToString());
                                輸出詳細內容();
                            }

                            空當沖.Send(下單名稱);
                        }
                    }

                    // 隔日沖時於隔日開盤市價平倉
                    if (!結算日集合.ContainsKey(Bars.Time[0].Date) && 成交時間 >= 結束交易時間) {
                        if (CurrentPosition.Side == EMarketPositionSide.Long) {
                            下單名稱 = "多單隔日沖全平";

                            if (設定_啟用詳細訊息) {
                                下單名稱 = 設定_策略名稱 + "_" + 下單名稱;
                                設定_輸出集合.Clear();
                                設定_輸出集合.Add("輸出下單", 下單名稱);
                                設定_輸出集合.Add("時間", m_資料時間);
                                設定_輸出集合.Add("成交價", Bars.Close[0].ToString());
                                設定_輸出集合.Add("下單規模", CurrentPosition.OpenLots.ToString());
                                輸出詳細內容();
                            }

                            多隔沖.Send(下單名稱);
                        }

                        if (CurrentPosition.Side == EMarketPositionSide.Short) {
                            下單名稱 = "空單隔日沖全平";

                            if (設定_啟用詳細訊息) {
                                下單名稱 = 設定_策略名稱 + "_" + 下單名稱;
                                設定_輸出集合.Clear();
                                設定_輸出集合.Add("輸出下單", 下單名稱);
                                設定_輸出集合.Add("時間", m_資料時間);
                                設定_輸出集合.Add("成交價", Bars.Close[0].ToString());
                                設定_輸出集合.Add("下單規模", CurrentPosition.OpenLots.ToString());
                                輸出詳細內容();
                            }

                            空隔沖.Send(下單名稱);
                        }
                    }
                }
            }

            前次PositionSide = CurrentPosition.Side;
        }
Esempio n. 4
0
        protected override void CalcBar() {
            //if (log.IsDebugEnabled) log.DebugFormat("Time={0}, CurrentBar={1}", Bars.BarUpdateTime.ToString("yyyy/MM/dd HH:mm:ss"), Bars.CurrentBar);
            // 只在 Data2 有資料後才處理分線
            if (Data2.CurrentBar <= 1 || Bars.Info.Resolution.Type != EResolution.Minute) {
                return;
            }

            漲跌.Value = Bars.Close[0] - Bars.Open[0];
            漲跌幅.Value = 100 * ((Bars.Close[0] - Bars.Close[1]) / Bars.Close[1]);
            上影線.Value = Bars.High[0] - Math.Max(Bars.Open[0], Bars.Close[0]);
            下影線.Value = Math.Min(Bars.Open[0], Bars.Close[0]) - Bars.Low[0];
            實體線.Value = Math.Abs(Bars.Open[0] - Bars.Close[0]);
            成交日期 = int.Parse(Bars.Time[0].Date.ToString("yyyyMMdd"));
            //成交時間 = int.Parse(Bars.BarUpdateTime.ToString("HHmmss"));
            //string m_資料時間 = Bars.BarUpdateTime.ToString("HH:mm:ss");
            成交時間 = int.Parse(Bars.Time[0].ToString("HHmmss"));
            string m_資料時間 = Bars.Time[0].ToString("HH:mm:ss");

            if (設定_啟用詳細訊息 && 設定_輸出集合 == null) {
                設定_輸出集合 = new Dictionary<string, string>();
                設定_輸出集合.Add("輸出記錄", "參數設定");
                設定_輸出集合.Add("策略名稱", 設定_策略名稱);
                設定_輸出集合.Add("策略版本", 設定_策略版本);
                #region 輸出指標策略參數
                設定_輸出集合.Add("啟用指標停損", 啟用指標停損.ToString());
                #endregion
                設定_輸出集合.Add("啟用順勢進場", 啟用順勢進場.ToString());
                設定_輸出集合.Add("順勢進場週間日", 順勢進場週間日);
                設定_輸出集合.Add("啟用逆勢進場", 啟用逆勢進場.ToString());
                設定_輸出集合.Add("逆勢進場週間日", 逆勢進場週間日);
                設定_輸出集合.Add("結算隔日進場月份", 結算隔日進場月份);
                設定_輸出集合.Add("資金_管理模式", 資金_管理模式.ToString());
                設定_輸出集合.Add("資金_風險比例", 資金_風險比例.ToString());
                設定_輸出集合.Add("資金_基本規模", 資金_基本規模.ToString());
                設定_輸出集合.Add("資金_跳空倍注", 資金_跳空倍注.ToString());
                設定_輸出集合.Add("資金_均多倍注", 資金_均多倍注.ToString());
                設定_輸出集合.Add("資金_均空倍注", 資金_均空倍注.ToString());
                設定_輸出集合.Add("資金_逆勢倍注", 資金_逆勢倍注.ToString());
                設定_輸出集合.Add("濾網_啟用多單", 濾網_啟用多單.ToString());
                設定_輸出集合.Add("濾網_啟用空單", 濾網_啟用空單.ToString());
                設定_輸出集合.Add("濾網_啟用當沖", 濾網_啟用當沖.ToString());
                設定_輸出集合.Add("濾網_開盤區間時間", 濾網_開盤區間時間.ToString());
                設定_輸出集合.Add("濾網_停單時間", 濾網_停單時間.ToString());
                設定_輸出集合.Add("加減碼_停損金額", 加減碼_停損金額.ToString());
                設定_輸出集合.Add("加減碼_停損點數", 停損點數.ToString());
                設定_輸出集合.Add("加減碼_加碼點數", 加減碼_加碼點數.ToString());
                設定_輸出集合.Add("加減碼_加碼次數", 加減碼_加碼次數.ToString());
                輸出詳細內容();
            }

            // 換日後需重算關鍵數值
            if (Bars.Time[0].Date > Bars.Time[1].Date && 重算日期 < 成交日期) {
                if (設定_啟用詳細訊息) {
                    設定_輸出集合.Clear();
                    設定_輸出集合.Add("輸出記錄", "新交易日");
                    設定_輸出集合.Add("原交易日", Bars.Time[1].Date.ToString("yyyy-MM-dd"));
                    設定_輸出集合.Add("新交易日", Bars.Time[0].Date.ToString("yyyy-MM-dd"));
                    設定_輸出集合.Add("資料時間", m_資料時間);
                    輸出詳細內容();
                }

                重算日期 = 0;
            }

            if (重算日期 == 0) {
                // 如非換日所引起的重算動作就跳出
                if (Bars.Time[0].Date < Bars.Time[1].Date) {
                    return;
                }

                昨最高 = Data2.High[0];
                昨最低 = Data2.Low[0];
                昨收盤 = Data2.Close[0];
                今開盤 = Bars.Open[0];
                開高價 = Bars.High[0];
                開低價 = Bars.Low[0];
                開收盤 = Bars.Close[0];
                開漲跌 = Bars.Open[0] - Data2.Close[0];
                開漲跌幅 = 100 * (開漲跌 / Data2.Close[0]);
                開盤區間高點 = 0;
                開盤區間低點 = int.MaxValue;
                ATR = AvgTrueRange.AverageTrueRange(this, 14, 0, 2);
                當日作多次數 = 0;
                當日作空次數 = 0;
                前次PositionSide = EMarketPositionSide.Flat;
                今最高 = Bars.High[0];
                今最低 = Bars.Low[0];
                今日停單 = false;
                週間日 = Bars.Time[0].DayOfWeek;

                // 資金管理:依模式計算下單規模
                double m_可用金額 = InitialCapital + NetProfit;
                double m_冒險金額 = m_可用金額 * 資金_風險比例;
                double m_市場風險 = 0;
                下單規模 = 資金_基本規模;

                switch (資金_管理模式) {
                    case 0: // 固定規模
                        下單規模 = 資金_基本規模;
                        break;
                    case 1: // 以保證金為基礎計算下單規模
                        m_市場風險 = Bars.Info.Margin;
                        下單規模 = Math.Max((int)Math.Floor(m_冒險金額 / m_市場風險), 資金_基本規模);
                        break;
                    case 2: // 以波動度為基礎計算下單規模
                        m_市場風險 = ATR * Bars.Info.BigPointValue;
                        下單規模 = Math.Max((int)Math.Floor(m_冒險金額 / m_市場風險), 資金_基本規模);
                        break;
                }

                if (資金_跳空倍注 > 0 && 開漲跌幅 >= 資金_跳空倍注) {
                    下單規模 *= 2;
                }

                if (資金_均多倍注 > 0 && 開收盤 > Data2.Close.Average(資金_均多倍注)) {
                    下單規模 *= 2;
                }

                if (資金_均空倍注 > 0 && 開收盤 < Data2.Close.Average(資金_均空倍注)) {
                    下單規模 *= 2;
                }

                #region 計算指標策略數值1
                // 原版 CDP 公式
                m_CDP = (昨最高 + 昨最低 + 昨收盤 * 2) * 0.25;
                m_AH = m_CDP + (昨最高 - 昨最低);
                m_NH = m_CDP * 2 - 昨最低;
                m_NL = m_CDP * 2 - 昨最高;
                m_AL = m_CDP - (昨最高 - 昨最低);

                // 老狼改良版,各線距離減半,績效將比原版成長數倍
                m_AH = (m_AH + m_NH) / 2;
                m_NH = (m_NH + m_CDP) / 2;
                m_AL = (m_AL + m_NL) / 2;
                m_NL = (m_NL + m_CDP) / 2;

                // 若 AH - AL 小於商品的 0.2% 幅度,今日就停單
                if (m_AH - m_AL < 今開盤 * 0.002) {
                    今日停單 = true;
                }

                if (設定_啟用詳細訊息) {
                    設定_輸出集合.Clear();
                    設定_輸出集合.Add("輸出記錄", "指標數值");
                    設定_輸出集合.Add("時間", m_資料時間);
                    設定_輸出集合.Add("AH", m_AH.ToString("N2"));
                    設定_輸出集合.Add("NH", m_NH.ToString("N2"));
                    設定_輸出集合.Add("CDP", m_CDP.ToString("N2"));
                    設定_輸出集合.Add("NL", m_NL.ToString("N2"));
                    設定_輸出集合.Add("AL", m_AL.ToString("N2"));
                    輸出詳細內容();
                }
                #endregion

                // 本交易日開倉,但不在進場月份中就停單
                if (結算日集合.ContainsKey(Bars.Time[1].Date) && !結算隔日進場月份集合[Bars.Time[0].Date.Month]) {
                    今日停單 = true;
                }

                if (設定_啟用詳細訊息 && 今日停單) {
                    設定_輸出集合.Clear();
                    設定_輸出集合.Add("輸出記錄", "今日停單");
                    設定_輸出集合.Add("日期", Bars.Time[0].ToString("yyyy-MM-dd"));
                    設定_輸出集合.Add("停單", 今日停單.ToString());
                    輸出詳細內容();
                }

                if (設定_啟用詳細訊息) {
                    設定_輸出集合.Clear();
                    設定_輸出集合.Add("輸出記錄", "下單規模");
                    設定_輸出集合.Add("口數", 下單規模.ToString());
                    輸出詳細內容();
                }

                重算日期 = 成交日期;
            }

            // 若仍無重算日期記錄就跳出
            if (重算日期 == 0) {
                return;
            }

            今最高 = Math.Max(今最高, Bars.High[0]);
            今最低 = Math.Min(今最低, Bars.Low[0]);

            #region 計算指標策略數值2

            #endregion

            // 開盤區間內只記錄高低價,不判斷訊號
            if (濾網_開盤區間時間 > 0 && 成交時間 <= 濾網_開盤區間時間) {
                開盤區間高點 = Math.Max(開盤區間高點, Bars.High[0]);
                開盤區間低點 = Math.Min(開盤區間低點, Bars.Low[0]);

                if (設定_啟用詳細訊息) {
                    if (m_資料時間 == "09:05:00") {
                        設定_輸出集合.Clear();
                        設定_輸出集合.Add("輸出記錄", "計算");
                        設定_輸出集合.Add("區間高點", 開盤區間高點.ToString());
                        設定_輸出集合.Add("AH", m_AH.ToString("N2"));
                        if (逆勢進場週間日集合[週間日]) {
                            string 判斷 = " (False)";
                            if (開低價 <= m_AL) {
                                判斷 = " (True)";
                            }
                            設定_輸出集合.Add("開低價", 開低價.ToString());
                            設定_輸出集合.Add("AL" + 判斷, m_AL.ToString("N2"));
                        }
                        設定_輸出集合.Add("資料時間", m_資料時間);
                        輸出詳細內容();
                    }
                }

                return;
            }


            if (CurrentPosition.Side == EMarketPositionSide.Long && 前次PositionSide == EMarketPositionSide.Flat) {
                當日作多次數++;
            }

            if (CurrentPosition.Side == EMarketPositionSide.Short && 前次PositionSide == EMarketPositionSide.Flat) {
                當日作空次數++;
            }

            // 判斷順勢進場新單訊號
            if (啟用順勢進場 == 1) {
                #region 順勢進場新單訊號
                if (CurrentPosition.Side == EMarketPositionSide.Flat && CurrentPosition.OpenTrades.Count == 0 && 成交時間 <= 濾網_停單時間 && !今日停單) {
                    if (濾網_啟用多單 == 1 && 當日作多次數 == 0 && Bars.Close[0] >= 開盤區間高點 && Bars.Close[0] >= m_AH && 順勢進場週間日集合[週間日]) {
                        下單名稱 = "突破作多";

                        if (設定_啟用詳細訊息) {
                            下單名稱 = 設定_策略名稱 + "_AH" + 下單名稱;
                            設定_輸出集合.Clear();
                            設定_輸出集合.Add("輸出下單", 下單名稱);
                            設定_輸出集合.Add("時間", m_資料時間);
                            設定_輸出集合.Add("成交價", Bars.Close[0].ToString());
                            設定_輸出集合.Add("AH", m_AH.ToString());
                            設定_輸出集合.Add("區間高點", 開盤區間高點.ToString());
                            設定_輸出集合.Add("今日高點", 今最高.ToString());
                            設定_輸出集合.Add("下單規模", 下單規模.ToString());
                            輸出詳細內容();
                        }

                        多單.Send(下單名稱, 下單規模);
                    }

                    if (濾網_啟用空單 == 1 && 當日作空次數 == 0 && Bars.Close[0] <= m_AL && Bars.Close[0] <= 開盤區間低點 && 順勢進場週間日集合[週間日]) {
                        下單名稱 = "跌破作空";

                        if (設定_啟用詳細訊息) {
                            下單名稱 = 設定_策略名稱 + "_AL" + 下單名稱;
                            設定_輸出集合.Clear();
                            設定_輸出集合.Add("輸出下單", 下單名稱);
                            設定_輸出集合.Add("時間", m_資料時間);
                            設定_輸出集合.Add("成交價", Bars.Close[0].ToString());
                            設定_輸出集合.Add("AL", m_AL.ToString());
                            設定_輸出集合.Add("區間低點", 開盤區間低點.ToString());
                            設定_輸出集合.Add("今日低點", 今最低.ToString());
                            設定_輸出集合.Add("下單規模", 下單規模.ToString());
                            輸出詳細內容();
                        }

                        空單.Send(下單名稱, 下單規模);
                    }
                }
                #endregion
            }

            // 判斷逆勢進場新單訊號
            if (啟用逆勢進場 == 1) {
                #region 逆勢進場新單訊號
                if (CurrentPosition.Side == EMarketPositionSide.Flat && CurrentPosition.OpenTrades.Count == 0 && 成交時間 <= 濾網_停單時間 && !今日停單) {
                    if (濾網_啟用多單 == 1 && 當日作多次數 == 0 && Bars.Close[0] >= m_AL && (m_AL - 開低價 >= 0) && 逆勢進場週間日集合[週間日]) {
                        下單名稱 = "反彈作多";

                        if (設定_啟用詳細訊息) {
                            下單名稱 = 設定_策略名稱 + "_AL" + 下單名稱;
                            設定_輸出集合.Clear();
                            設定_輸出集合.Add("輸出下單", 下單名稱);
                            設定_輸出集合.Add("時間", m_資料時間);
                            設定_輸出集合.Add("成交價", Bars.Close[0].ToString());
                            設定_輸出集合.Add("AL", m_AL.ToString());
                            設定_輸出集合.Add("開低價", 開低價.ToString());
                            設定_輸出集合.Add("下單規模", ((資金_逆勢倍注 == 1) ? 下單規模 * 2 : 下單規模).ToString());
                            輸出詳細內容();
                        }

                        多單.Send(下單名稱, (資金_逆勢倍注 == 1) ? 下單規模 * 2 : 下單規模);
                    }

                    // 穿頭殺回作空
                    if (濾網_啟用空單 == 1 && 當日作空次數 == 0 && Bars.Close[0] <= m_AH && (開高價 - m_AH >= 0) && 逆勢進場週間日集合[週間日]) {
                        下單名稱 = "殺回作空";

                        if (設定_啟用詳細訊息) {
                            下單名稱 = 設定_策略名稱 + "_AH" + 下單名稱;
                            設定_輸出集合.Clear();
                            設定_輸出集合.Add("輸出下單", 下單名稱);
                            設定_輸出集合.Add("時間", m_資料時間);
                            設定_輸出集合.Add("成交價", Bars.Close[0].ToString());
                            設定_輸出集合.Add("AH", m_AH.ToString());
                            設定_輸出集合.Add("開高價", 開高價.ToString());
                            設定_輸出集合.Add("下單規模", ((資金_逆勢倍注 == 1) ? 下單規模 * 2 : 下單規模).ToString());
                            輸出詳細內容();
                        }

                        空單.Send(下單名稱, (資金_逆勢倍注 == 1) ? 下單規模 * 2 : 下單規模);
                    }
                }
                #endregion
            }

            // 判斷多單是否需要加碼
            if (CurrentPosition.Side == EMarketPositionSide.Long && CurrentPosition.OpenTrades.Count <= 加減碼_加碼次數) {
                if (Bars.Close[0] >= 最後進場部位.Price + 加減碼_加碼點數) {
                    下單名稱 = "多單加碼";

                    if (設定_啟用詳細訊息) {
                        下單名稱 = 設定_策略名稱 + "_" + 下單名稱;
                        設定_輸出集合.Clear();
                        設定_輸出集合.Add("輸出下單", 下單名稱);
                        設定_輸出集合.Add("時間", m_資料時間);
                        設定_輸出集合.Add("成交價", Bars.Close[0].ToString());
                        設定_輸出集合.Add("最後進場點位", 最後進場部位.Price.ToString());
                        設定_輸出集合.Add("加碼點位", (最後進場部位.Price + 加減碼_加碼點數).ToString());
                        設定_輸出集合.Add("下單規模", ((資金_逆勢倍注 == 1) ? 下單規模 * 2 : 下單規模).ToString());
                        輸出詳細內容();
                    }

                    多單.Send(下單名稱, 最後進場部位.Contracts);
                }
            }

            // 判斷空單是否需要加碼
            if (CurrentPosition.Side == EMarketPositionSide.Short && CurrentPosition.OpenTrades.Count <= 加減碼_加碼次數) {
                if (Bars.Close[0] <= 最後進場部位.Price - 加減碼_加碼點數) {
                    下單名稱 = "空單加碼";

                    if (設定_啟用詳細訊息) {
                        下單名稱 = 設定_策略名稱 + "_" + 下單名稱;
                        設定_輸出集合.Clear();
                        設定_輸出集合.Add("輸出下單", 下單名稱);
                        設定_輸出集合.Add("時間", m_資料時間);
                        設定_輸出集合.Add("成交價", Bars.Close[0].ToString());
                        設定_輸出集合.Add("最後進場點位", 最後進場部位.Price.ToString());
                        設定_輸出集合.Add("加碼點位", (最後進場部位.Price - 加減碼_加碼點數).ToString());
                        設定_輸出集合.Add("下單規模", ((資金_逆勢倍注 == 1) ? 下單規模 * 2 : 下單規模).ToString());
                        輸出詳細內容();
                    }

                    空單.Send(下單名稱, 最後進場部位.Contracts);
                }
            }

            // 判斷多單是否需要停損
            if (CurrentPosition.Side == EMarketPositionSide.Long && CurrentPosition.OpenTrades.Count > 0) {
                if (Bars.Close[0] <= 最後進場部位.Price - 停損點數) {
                    下單名稱 = "多單停損";

                    if (設定_啟用詳細訊息) {
                        下單名稱 = 設定_策略名稱 + "_" + 下單名稱;
                        設定_輸出集合.Clear();
                        設定_輸出集合.Add("輸出下單", 下單名稱 + "_虧損");
                        設定_輸出集合.Add("時間", m_資料時間);
                        設定_輸出集合.Add("成交價", Bars.Close[0].ToString());
                        設定_輸出集合.Add("最後進場點位", 最後進場部位.Price.ToString());
                        設定_輸出集合.Add("停損點位", (最後進場部位.Price - 停損點數).ToString());
                        輸出詳細內容();
                    }

                    多停.Send(下單名稱, 最後進場部位.Contracts);
                }

                #region 多單指標停損訊號
                if (啟用指標停損 == 1 && Bars.Close[0] <= m_NH) {
                    下單名稱 = "多單停損";

                    if (設定_啟用詳細訊息) {
                        下單名稱 = 設定_策略名稱 + "_" + 下單名稱;
                        設定_輸出集合.Clear();
                        設定_輸出集合.Add("輸出下單", 下單名稱 + "_NH");
                        設定_輸出集合.Add("時間", m_資料時間);
                        設定_輸出集合.Add("成交價", Bars.Close[0].ToString());
                        設定_輸出集合.Add("最後進場點位", 最後進場部位.Price.ToString());
                        設定_輸出集合.Add("NH", m_NH.ToString());
                        輸出詳細內容();
                    }

                    多停.Send(下單名稱, 最後進場部位.Contracts);
                }
                #endregion
            }

            // 判斷空單是否需要停損
            if (CurrentPosition.Side == EMarketPositionSide.Short && CurrentPosition.OpenTrades.Count > 0) {
                if (Bars.Close[0] >= 最後進場部位.Price + 停損點數) {
                    下單名稱 = "空單停損";

                    if (設定_啟用詳細訊息) {
                        下單名稱 = 設定_策略名稱 + "_" + 下單名稱;
                        設定_輸出集合.Clear();
                        設定_輸出集合.Add("輸出下單", 下單名稱 + "_虧損");
                        設定_輸出集合.Add("時間", m_資料時間);
                        設定_輸出集合.Add("成交價", Bars.Close[0].ToString());
                        設定_輸出集合.Add("最後進場點位", 最後進場部位.Price.ToString());
                        設定_輸出集合.Add("停損點位", (最後進場部位.Price + 停損點數).ToString());
                        輸出詳細內容();
                    }

                    空停.Send(下單名稱, 最後進場部位.Contracts);
                }

                #region 空單指標停損訊號
                if (啟用指標停損 == 1 && Bars.Close[0] >= m_NL) {
                    下單名稱 = "空單停損";

                    if (設定_啟用詳細訊息) {
                        下單名稱 = 設定_策略名稱 + "_" + 下單名稱;
                        設定_輸出集合.Clear();
                        設定_輸出集合.Add("輸出下單", 下單名稱 + "_NL");
                        設定_輸出集合.Add("時間", m_資料時間);
                        設定_輸出集合.Add("成交價", Bars.Close[0].ToString());
                        設定_輸出集合.Add("最後進場點位", 最後進場部位.Price.ToString());
                        設定_輸出集合.Add("NL", m_NL.ToString());
                        輸出詳細內容();
                    }

                    空停.Send(下單名稱, 最後進場部位.Contracts);
                }
                #endregion
            }

            // 當沖/隔日沖平倉
            if (CurrentPosition.Side != EMarketPositionSide.Flat && CurrentPosition.OpenTrades.Count > 0) {
                // 當沖時於指定出場時間全平
                if (濾網_啟用當沖 == 1 && 成交時間 >= 當沖出場時間) {
                    if (CurrentPosition.Side == EMarketPositionSide.Long) {
                        下單名稱 = "多單當沖全平";

                        if (設定_啟用詳細訊息) {
                            下單名稱 = 設定_策略名稱 + "_" + 下單名稱;
                            設定_輸出集合.Clear();
                            設定_輸出集合.Add("輸出下單", 下單名稱);
                            設定_輸出集合.Add("時間", m_資料時間);
                            設定_輸出集合.Add("成交價", Bars.Close[0].ToString());
                            設定_輸出集合.Add("下單規模", CurrentPosition.OpenLots.ToString());
                            輸出詳細內容();
                        }

                        多當沖.Send(下單名稱);
                    }

                    if (CurrentPosition.Side == EMarketPositionSide.Short) {
                        下單名稱 = "空單當沖全平";

                        if (設定_啟用詳細訊息) {
                            下單名稱 = 設定_策略名稱 + "_" + 下單名稱;
                            設定_輸出集合.Clear();
                            設定_輸出集合.Add("輸出下單", 下單名稱);
                            設定_輸出集合.Add("時間", m_資料時間);
                            設定_輸出集合.Add("成交價", Bars.Close[0].ToString());
                            設定_輸出集合.Add("下單規模", CurrentPosition.OpenLots.ToString());
                            輸出詳細內容();
                        }

                        空當沖.Send(下單名稱);
                    }
                } else {
                    // 結算當日強制於當沖出場時間平倉
                    if (結算日集合.ContainsKey(Bars.Time[0].Date) && 成交時間 >= 當沖出場時間) {
                        if (CurrentPosition.Side == EMarketPositionSide.Long) {
                            下單名稱 = "多單結算日全平";

                            if (設定_啟用詳細訊息) {
                                下單名稱 = 設定_策略名稱 + "_" + 下單名稱;
                                設定_輸出集合.Clear();
                                設定_輸出集合.Add("輸出下單", 下單名稱);
                                設定_輸出集合.Add("時間", m_資料時間);
                                設定_輸出集合.Add("成交價", Bars.Close[0].ToString());
                                設定_輸出集合.Add("下單規模", CurrentPosition.OpenLots.ToString());
                                輸出詳細內容();
                            }

                            多當沖.Send(下單名稱);
                        }

                        if (CurrentPosition.Side == EMarketPositionSide.Short) {
                            下單名稱 = "空單結算日全平";

                            if (設定_啟用詳細訊息) {
                                下單名稱 = 設定_策略名稱 + "_" + 下單名稱;
                                設定_輸出集合.Clear();
                                設定_輸出集合.Add("輸出下單", 下單名稱);
                                設定_輸出集合.Add("時間", m_資料時間);
                                設定_輸出集合.Add("成交價", Bars.Close[0].ToString());
                                設定_輸出集合.Add("下單規模", CurrentPosition.OpenLots.ToString());
                                輸出詳細內容();
                            }

                            空當沖.Send(下單名稱);
                        }
                    }

                    // 隔日沖時於隔日開盤市價平倉
                    if (!結算日集合.ContainsKey(Bars.Time[0].Date) && 成交時間 >= 濾網_停單時間) {
                        if (CurrentPosition.Side == EMarketPositionSide.Long) {
                            下單名稱 = "多單隔日沖全平";

                            if (設定_啟用詳細訊息) {
                                下單名稱 = 設定_策略名稱 + "_" + 下單名稱;
                                設定_輸出集合.Clear();
                                設定_輸出集合.Add("輸出下單", 下單名稱);
                                設定_輸出集合.Add("時間", m_資料時間);
                                設定_輸出集合.Add("成交價", Bars.Close[0].ToString());
                                設定_輸出集合.Add("下單規模", CurrentPosition.OpenLots.ToString());
                                輸出詳細內容();
                            }

                            多隔沖.Send(下單名稱);
                        }

                        if (CurrentPosition.Side == EMarketPositionSide.Short) {
                            下單名稱 = "空單隔日沖全平";

                            if (設定_啟用詳細訊息) {
                                下單名稱 = 設定_策略名稱 + "_" + 下單名稱;
                                設定_輸出集合.Clear();
                                設定_輸出集合.Add("輸出下單", 下單名稱);
                                設定_輸出集合.Add("時間", m_資料時間);
                                設定_輸出集合.Add("成交價", Bars.Close[0].ToString());
                                設定_輸出集合.Add("下單規模", CurrentPosition.OpenLots.ToString());
                                輸出詳細內容();
                            }

                            空隔沖.Send(下單名稱);
                        }
                    }
                }
            }

            前次PositionSide = CurrentPosition.Side;
        }
        protected override void CalcBar() {
            成交日期 = int.Parse(Bars.Time[0].Date.ToString("yyyyMMdd"));
            成交時間 = int.Parse(Bars.BarUpdateTime.ToString("HHmmss"));
            string m_資料時間 = Bars.Time[0].ToString("HH:mm:ss");

            if (設定_啟用詳細訊息 && 設定_輸出集合 == null) {
                設定_輸出集合 = new Dictionary<string, string>();
                設定_輸出集合.Add("OutputLogs", "參數設定");
                設定_輸出集合.Add("策略名稱", 設定_策略名稱);
                設定_輸出集合.Add("策略版本", 設定_策略版本);

                設定_輸出集合.Add("開始交易時間", Convert時間(開始交易時間));
                設定_輸出集合.Add("結束交易時間", Convert時間(結束交易時間));
                設定_輸出集合.Add("當沖全平時間", Convert時間(當沖全平時間));

                設定_輸出集合.Add("下單口數", 下單口數.ToString());
                設定_輸出集合.Add("停損點數", 停損點數.ToString());
                設定_輸出集合.Add("停利點數", 停利點數.ToString());

                輸出詳細內容();
            }
            // 換日後需重算關鍵數值
            if (Bars.Time[0].Date > Bars.Time[1].Date && 重算日期 < 成交日期) {
                if (設定_啟用詳細訊息) {
                    設定_輸出集合.Clear();
                    設定_輸出集合.Add("OutputLogs", "新交易日");
                    設定_輸出集合.Add("原交易日", Bars.Time[1].Date.ToString("yyyy-MM-dd"));
                    設定_輸出集合.Add("新交易日", Bars.Time[0].Date.ToString("yyyy-MM-dd"));
                    設定_輸出集合.Add("資料時間", m_資料時間);
                    輸出詳細內容();
                }

                重算日期 = 0;
            }


            if (重算日期 == 0) {
                // 如非換日所引起的重算動作就跳出
                if (Bars.Time[0].Date < Bars.Time[1].Date) {
                    return;
                }

                __d突破價 = 0;
                __dMaxPrice = 0;

                當日作多次數 = 0;
                當日作空次數 = 0;
                前次PositionSide = EMarketPositionSide.Flat;


                重算日期 = 成交日期;
            }
            // 若仍無重算日期記錄就跳出
            if (重算日期 == 0) {
                return;
            }

            if (CurrentPosition.Side == EMarketPositionSide.Long && 前次PositionSide == EMarketPositionSide.Flat) {
                當日作多次數++;
            }

            if (CurrentPosition.Side == EMarketPositionSide.Short && 前次PositionSide == EMarketPositionSide.Flat) {
                當日作空次數++;
            }
            if (CurrentPosition.Side == EMarketPositionSide.Flat && 前次PositionSide == EMarketPositionSide.Long) {
                //多單平倉
            }

            double dOpen = Bars.Open[0];
            double dHigh = Bars.High[0];
            double dLow = Bars.Low[0];
            double dClose = Bars.Close[0];
            double dVolume = Bars.Volume[0];

            //Console.WriteLine(string.Format("量_({0}){1}", Convert時間(成交時間), dVolume));

            //--- 觸發多單進場 (目前版本無倉且符合條件才下單)
            if (CurrentPosition.Side == EMarketPositionSide.Flat && CurrentPosition.OpenTrades.Count == 0) { //無倉狀態

                if (成交時間 >= 開始交易時間 && 成交時間 <= 結束交易時間) {
                    // 判斷突破條件:當該跟黑K 且 量>1000 且 當跟最低價<  前15跟最低價最小值
                    if (dVolume > 1000) { //量>1000,回測系統沒有一分K的量
                        //Console.WriteLine(string.Format("量大1000_({0}){1}>1000", Convert時間(成交時間), dVolume));
                        double dLow_ = Bars.Low[1];
                        if (成交時間 > 90100) { //取前15跟最低價
                            for (int i = 2; i <= 15; i++) {
                                dLow_ = Math.Min(dLow_, Bars.Low[i]);
                            }
                        }
                        double dLow15 = dLow_;// Bars.Low.Lowest(15);
                        //double dLow15 = Bars.Low.Lowest(15);
                        if (dLow <= dLow15) {
                            //Console.WriteLine(string.Format("跌破前15跟新低_({0}){1}<{2}", Convert時間(成交時間), dLow, dLow15));
                            if (dClose < dOpen) { // 黑K
                                //Console.WriteLine(string.Format("黑K_({0}){1}<{2}", Convert時間(成交時間), dClose, dOpen));

                                __d突破價 = dHigh;

                                下單名稱 = "偵測突破";
                                if (設定_啟用詳細訊息) {
                                    下單名稱 = 設定_策略名稱 + "_" + 下單名稱;
                                    設定_輸出集合.Clear();
                                    設定_輸出集合.Add("OutputLogs", 下單名稱);
                                    設定_輸出集合.Add("時間", m_資料時間);
                                    設定_輸出集合.Add("突破價", __d突破價.ToString());
                                    輸出詳細內容();
                                }
                            }
                        }

                    }

                    if (dClose > __d突破價 && __d突破價 > 0) {


                        下單名稱 = "突破作多";
                        if (設定_啟用詳細訊息) {
                            下單名稱 = 設定_策略名稱 + "_" + 下單名稱;
                            設定_輸出集合.Clear();
                            設定_輸出集合.Add("OutputOrders", 下單名稱);
                            設定_輸出集合.Add("時間", m_資料時間);
                            設定_輸出集合.Add("成交價", Bars.Close[0].ToString());
                            設定_輸出集合.Add("突破價", __d突破價.ToString());
                            設定_輸出集合.Add("下單口數", 下單口數.ToString());
                            輸出詳細內容();
                        }

                        __d突破價 = 0; //進場後後歸零,重新找新的

                        多單.Send(下單名稱, 下單口數);
                    }


                }
            }
            //--- 多單平倉,過下單時間後也要執行平倉動作
            if (CurrentPosition.Side == EMarketPositionSide.Long) {

                double dOpenPrice = 最後進場部位.Price;

                // --- 1. 多單停利
                if (Bars.Close[0] >= dOpenPrice + 停利點數) {
                    //__d突破價 = 0; // 1.停利須歸零
                    下單名稱 = "多單停利";
                    if (設定_啟用詳細訊息) {
                        下單名稱 = 設定_策略名稱 + "_" + 下單名稱;
                        設定_輸出集合.Clear();
                        設定_輸出集合.Add("OutputOrders", 下單名稱 + "_停利");
                        設定_輸出集合.Add("時間", m_資料時間);
                        設定_輸出集合.Add("成交價", Bars.Close[0].ToString());
                        設定_輸出集合.Add("最後進場點位", 最後進場部位.Price.ToString());
                        設定_輸出集合.Add("停利點位", (最後進場部位.Price + 停利點數).ToString());
                        輸出詳細內容();
                    }
                    多停.Send(下單名稱);

                }
                // --- 2. 移動停損               

                if (__dMaxPrice == 0) { //成交後初值須填入
                    __dMaxPrice = dOpenPrice;
                }
                if (dClose > dOpenPrice && dClose > __dMaxPrice) {
                    __dMaxPrice = dClose; //更新買進後最高價
                } else {
                    double dDiff = __dMaxPrice - dClose;
                    if (dDiff >= 停損點數) { //移動停損
                        //__d突破價 = 0; // 2.停損須歸零
                        下單名稱 = "移動停損";
                        if (設定_啟用詳細訊息) {
                            下單名稱 = 設定_策略名稱 + "_" + 下單名稱;
                            設定_輸出集合.Clear();
                            設定_輸出集合.Add("OutputOrders", 下單名稱 + "_多單");
                            設定_輸出集合.Add("時間", m_資料時間);
                            設定_輸出集合.Add("成交價", Bars.Close[0].ToString());
                            設定_輸出集合.Add("最後進場點位", 最後進場部位.Price.ToString());
                            設定_輸出集合.Add("高點", __dMaxPrice.ToString());
                            設定_輸出集合.Add("平倉點位", (最後進場部位.Price - 停損點數).ToString());
                            輸出詳細內容();
                        }

                        __dMaxPrice = 0;

                        多停.Send(下單名稱);
                    }
                }

                // --- 3.時間到時平倉
                if (成交時間 >= 當沖全平時間) {  //全部平倉
                    下單名稱 = "多單當沖全平";
                    //__d突破價 = 0; // 3.平倉須歸零
                    if (設定_啟用詳細訊息) {
                        下單名稱 = 設定_策略名稱 + "_" + 下單名稱;
                        設定_輸出集合.Clear();
                        設定_輸出集合.Add("OutputOrders", 下單名稱);
                        設定_輸出集合.Add("時間", m_資料時間);
                        設定_輸出集合.Add("成交價", Bars.Close[0].ToString());
                        設定_輸出集合.Add("平倉口數", CurrentPosition.OpenLots.ToString());
                        輸出詳細內容();
                    }
                    多停.Send(下單名稱);
                }
            }

            前次PositionSide = CurrentPosition.Side;
        }
        protected override void StartCalc() {

            前次PositionSide = EMarketPositionSide.Flat;
            重算日期 = 0;
        }