如何写自己的交易策略

基本概念:

开始实践:

1.     写一个指标

2.     我们有了一个MA指标,现在利用它来实现一个双均线交叉交易策略吧!

3.     怎样使用我们的策略呢?

应注意的问题:

1.     在实盘策略中,不要使用未来数据

2.     在实盘状态下,与未连接行情的模拟状态会有所不同:

3.     ValueSeries 类的AddOrFlush()方法的错误用法:

 

如何写自己的交易策略

 

编写自己的交易策略需要一些c#知识,在此不多做介绍。List<T>等数据结构均可在策略中使用。


基本概念:

1. DateSeries(日期序列):

DateSeries 是一个日期类型的“数组”。

2. ValueSerie(值序列):

ValueSerie可以理解为:一个可绘制在窗口区的 double 类型的 “数组”。

值序列[0]表示序列中的倒数第一个值。

值序列[1]表示序列中的倒数第二个值。

……

值序列[n]表示序列中的倒数第 n + 1个值。

3. Indicator(指标):

Indicator是每收到一个行情数据时,都会按其实现逻辑自动计算的值序列。

4. ContractBarSeries(合约):

ContractBarSeries是包含 Open、High、Low、Close、Vol、OI值序列及合约信息的集合。

5. Strategy(策略):

Strategy 是每收到一个行情数据时,都会按其实现逻辑自动计算并发单的ContractBarSeries 的集合。

开始实践:

1.写一个指标

打开VS并新建一个项目—“类库(.NET Framework)”。选择“”菜单下的“配置管理”命令。在弹出的“配置管理器”对话框中,在“平台”的下拉列表框中选择“<新建...>”。那么“平台”下的选项会变为“x64”,单击“关闭”按钮关闭对话框。将“Base.dll”文件复制到程序目录中,并添加对其的引用。添加using TradePlat语句。

指标代码如下:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

using TradePlat;

 

namespace IndicatorLib

{

    ///<summary>

    ///计算简单移动平均 SMA,通过 R 属性返回计算结果

    ///</summary>

    publicclassMA : Indicator

    {

        ///<summary>

        ///

        ///</summary>

        ///<paramname="strategy 指标所属的策略"></param>

        ///<paramname="str 输入序列的名称。如:Close“High”"></param>

        ///<paramname="p 计算周期"></param>

        public MA(ContractBarSeries contractBarSeries, string str) : base(contractBarSeries, str)

        {

        }

 

        public MA(ValueSeries vs) : base(vs)

        {

        }

 

        privateint _period;

        privateValueSeries _outSeries = newValueSeries(0);   //输出系列

 

        ///<summary>

        ///指标名--指标名 + 参数

        ///</summary>

        publicoverridestring Name

        {

            get => "MA:" + Period;

        }

 

        ///<summary>

        ///指标计算周期--小于零则返回 0

        ///</summary>

        publicint Period

        {

            get => _period;

            set

            {

                if (value < 0)

                {

                    _period = 0;

                }

                else

                {

                    _period = value;

                }

            }

        }

 

        //计算过程中使用的变量

        double sum;    //

 

        ///<summary>

        ///计算并更新指标

        ///当指标计算参数或输入系列长度小于等于零时,返回包含零个元素的 ValueSeries(0)

        ///</summary>

        ///<param name="inBar"></param>

        publicoverridevoid UpData(bool inBar)

        {

            if (_period <= 0 || _inSeries.Length <= 0)

            {

                _outSeries = newValueSeries(0);

            }

            else

            {

                if (_inSeries.Length < _period)

                {

                    _outSeries.AddOrFlush(double.NaN, inBar);

                }

                else

                {

                    sum = 0;

                    for (int i = 0; i < _period; i++)

                    {

                        sum += _inSeries[i];

                    }

 

                    _outSeries.AddOrFlush(sum /_period, inBar);

                }

            }

        }

 

        ///<summary>

        ///返回输出系列

        ///</summary>

        publicoverrideValueSeries R

        {

            get => _outSeries;

        }

    }

}

2. 我们有了一个MA指标,现在利用它来实现一个双均线交叉交易策略吧!

打开VS并新建一个项目—“类库(.NET Framework)”。选择“”菜单下的“配置管理”命令。在弹出的“配置管理器”对话框中,在“平台”的下拉列表框中选择“<新建...>”。那么“平台”下的选项会变为“x64”,单击“关闭”按钮关闭对话框。将“Base.dll”文件及上一步生成的“IndicatorLib.dll”文件复制到程序目录中,并添加对他们的引用。添加usingSystem.ComponentModel;using TradePlat;using IndicatorLib;语句。

策略代码如下:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

using System.Windows.Forms;

using System.IO;

using System.ComponentModel;

using TradePlat;

using IndicatorLib;

 

namespace StrategyLib

{

    ///<summary>

    ///

    ///</summary>

    publicclassTwoSma : Strategy

    {

 

        privateContractBarSeries _bs;

 

        privateMA ma;

        privateMA ma2;

 

        privateVolume vol;

 

        [CategoryAttribute("参数"), DescriptionAttribute("短周期-多少个Bar")]

        publicint Period1

        {

            get => ma.Period;

            set

            {

                if (value < 0)

                {

                    ma.Period = 0;

                }

                else

                {

                    ma.Period = value;

                }

            }

        }

 

        [CategoryAttribute("参数"), DescriptionAttribute("长周期-多少个Bar")]

        publicint Period2

        {

            get => ma2.Period;

            set

            {

                if (value < 0)

                {

                    ma2.Period = 0;

                }

                else

                {

                    ma2.Period = value;

                }

            }

        }

 

        ///<summary>

        ///

        ///</summary>

        ///<paramname="bs"></param>

        ///<paramname="str"></param>

        ///<paramname="p"></param>

        public TwoSma(ContractBarSeries[] bsArray) : base(bsArray)

        {

            if (bsArray != null && bsArray.Length > 0)

            {

                _bs = bsArray[0];

                AddToCurrentWindow(_bs);

                ma = newMA(_bs, "Close");

                AddToCurrentWindow(ma);          //将指标 ma 添加到当前窗口区以显示

 

                ma2 = newMA(_bs, "Close");

                AddToCurrentWindow(ma2);       //将指标 ma2 添加到当前窗口区以显示

 

                //vol = newVolume(_bs);

                //vol.R.IsPillar = true;                      //以差状图形式绘制成交量

                //AddToNewWindow(vol);            //将指标 vol 添加到新的窗口区以显示

            }

        }

 

        ///<summary>

        ///策略名称

        ///</summary>

        publicoverridestring Name

        {

            get => this.GetType().ToString();

        }

 

        publicoverridestring KeyName

        {

            get => _bs.InstrumentName;

        }

 

        ///<summary>

        ///策略参数的字符串表示

        ///</summary>

        publicoverridestring ParameterString

        {

            get

            {

                return"Period1:" + Period1 + ", Period2:" + Period2 + ", " + base.ParameterString;

            }

        }

 

        ///<summary>

        ///返回序列--测试时用

        ///</summary>

        [Browsable(false)]

        publicValueSeries Return

        {

            get => ma.R;

        }

 

        ///<summary>

        ///策略具体执行的内容

        ///</summary>

        ///<paramname="inBar"></param>

        protectedoverridevoid Execute(bool inBar)

        {

            if (Period1 == 0 || Period2 == 0)

            {

                OnError("参数 Period 设置有误!");

            }

            else

            {

                ma.UpDataIndicator(inBar);

                ma2.UpDataIndicator(inBar);

 

                if (_bs.NoHasLong

                        && (ma.R[2]<= ma2.R[2] && ma.R[1] > ma2.R[1]))//上穿

                {

                    _bs.BuyToCover(_bs.Open[0],"s1", Lots);

                    _bs.Buy(_bs.Open[0], "b1", Lots);

                }

 

                if (_bs.NoHasShort

                    && (ma.R[2] >=ma2.R[2] && ma.R[1] < ma2.R[1]))//下穿

                {

                    _bs.Sell(_bs.Open[0], "b1", Lots);

                    _bs.SellShort(_bs.Open[0], "s1", Lots);

                }

            }

        }

    //

}

3. 怎样使用我们的策略呢?

将“IndicatorLib.dll”文件复制到程序目录下,将“StrategyLib.dll”文件复制到程序目录下的“strategies”文件夹下。现在运行我们的程序就可以在程序中加载刚刚实现的策略了。


应注意的问题:

1. 在实盘策略中,不要使用未来数据

像 _bs.High[0]、_bs.Low[0] 这样的数据我们称为:未来数据,它们表示当前这根 Bar 的最高价、最低价。由于这根 Bar 并未结束,所以它的最高价、最低价仍在变化之中,尚不确定。

由于 _bs.Open[0] 在这根一出现时,便已确定。所以它不是未来数据。_bs.Close[0] 则代表这根 Bar 的最新价,所以它也不是未来数据。


2.在实盘状态下,与未连接行情的模拟状态会有所不同: 

 

if (_bs.Close[0] >= BuyPosition[0]) //在实盘状态下表示最新价 >= BuyPosition[0]

{

……

}

 

if(_bs.Close[0] >= BuyPosition[0]) //在静态状态下表示收盘价 >= BuyPosition[0]

{

……

}

由于这种情况的存在,所以在接入实盘数据前要求输入目前实际持仓的信息。


3.ValueSeries 类的AddOrFlush()方法的错误用法:

val = (_mPeriod *_inSeries[0] + (_nPeriod - _mPeriod) * _outSeries[0]) / _nPeriod;

_outSeries.AddOrFlush(val,inBar);

错误的原因:指标每 tick 会运行一次,上面代码是用 _outSeries[0] 更新  _outSeries[0],得到是当前Bar 的累积值。

正确的写法:

if (!inBar)

{

      _outSeries.Add(double.NaN);

}

val = (_mPeriod *_inSeries[0] + (_nPeriod - _mPeriod) * _outSeries[1]) / _nPeriod;

_outSeries.Flush(val);

猜你喜欢

转载自blog.csdn.net/hjjfoxok/article/details/80636472