欢迎您光临博庭社区!

 找回密码
 立即注册
楼主: hslixuexue

自制《金语言初级教程》--从0开始学习金语言   [复制链接]

Rank: 3Rank: 3

发表于 2013-8-30 17:30:34 |显示全部楼层
本帖最后由 hslixuexue 于 2013-8-31 09:39 编辑

(十)开发DLL的详细例子
这里例子是使用VS2012制作的。
1. 首先创建Win32的工程项目,项目名称是MyDll
2. 项目设置成DLL
3. TimeType, STKDATA, STKDATAEx,等等上述数据结构拷贝到MyDll.cpp
4. 添加用户函数MYMACLOSE, 计算 N 日均线
//计算收盘价的均价,一个常数参数,表示计算周期
//调用方法:
// "FOXFUNC@MYMACLOSE"(5)
extern "C" __declspec(dllexport) int WINAPI MYMACLOSE(CALCINFO* pData)
{//->指针指向,&&and
  if ( pData->m_pfParam1 &&//参数1有效
          pData->m_nParam1Start<0 &&//参数1为常数
          pData->m_pfParam2==NULL )   //仅有一个参数
   {
         float fParam = *pData->m_pfParam1; //
         int nPeriod = (int)fParam;  //参数1
         if(nPeriod>0)
         {
              float fTotal;
              int i, j;
              for ( i = nPeriod-1; i < pData->m_nNumData; i++ )//计算nPeriod周期的均线,数据从nPeriod-1开始有效
              {
                    fTotal = 0.0f;
                    for ( j = 0; j < nPeriod; j++ ) //累加
                          fTotal += pData->m_pData[i-j].m_fClose;
              pData->m_pResultBuf = fTotal/nPeriod;   //平均
              }
              return nPeriod-1;
         }
   }
   return -1;
}
5. 设置项目的输出路径为软件安装目录下的 FmlDll 下,输出名称为 MyDll.dll。这一步可以省略,编译后手动拷贝dll到软件的FmlDll目录也可以。
6. 编译后,直接运行软件,或者在Debugging调试Command处添加软件的启动路径
7. 创建公式 测试DLL,并编译
8. 拖放到图上运行。
二、新格式 DLL调用。

新的金魔方DLL接口不但兼容老飞狐DLL格式,而且新增了对普通任意DLL的支持。只要在公式中描述清楚函数的定义,就能在金魔方中使用它们。

老的一套DLL调用方式只能工作在逐行模式,而新的一套用法只能工作在逐根模式下所。用到新模式的时候,必须声明#RunMode Run_by_bar 或者 #trade

新的公式逐根运行模式每次只计算新增数据,不需要整条序列重新运算,这样可以大大提升效率。有鉴于此,DLL调用也有了新的格式。
(一)逐根模式DLL接口声明:
扩展函数用windows 32位动态链接库实现,建议使用Microsoft Visual C++编程。
只能用于逐根运行模式#Run_By_Bar。调用前需要extern声明:extern 返回值类型 函数名(参数类型 参数,...);
调用时直接调用函数名,与普通函数调用方式一样。DLL名称和函数名可以自己定义。使用时必须将DLL放在软件安装目录下的FmlDll子目录下。
// C 代码里的声明
extern "C" __declspec(dllexport) void WINAPI my_ma2(float* pResultBuffer, float* pDataBuffer, int n, int barpos)
// 公式里面的声明,金语言代码里面的声明
#RunMode Run_by_bar
extern 'MyDll2.dll' void  my_ma2(NumericSeries ResultBuffer, NumericSeries DataBuffer, int n, int barpos);
(二)DLL函数格式:DLL名称和函数名都是大小写敏感的,代码声明和公式调用时需要匹配。参数的个数和名称都没有限制,支持基础的数据类型float, double, int,BOOL, LONG, DWORD, float*, LPCWSTR,注意序列类型只能是 float*, 单值类型则是通用的。
(三)DLL的返回值:新格式DLL可返回单值,序列和数组。单值类型大致分为两种:数值类型(整数、小数)和字符串类型,可以通过函数返回值直接返回。
C语言返回单值类型的例子
extern "C" __declspec(dllexport) int WINAPI my_test1()
{       return 1;}//返回整数
extern "C" __declspec(dllexport) float WINAPI my_test2()
{  return 2.0f;}//返回浮点
extern "C" __declspec(dllexport) LPCWSTR WINAPI my_test3()
{    return L"TEST STRING";}//返回字符串
相应的金语言公式调用例子
#MAINCHART
#Run_By_Bar
extern 'MyDll2.dll' int my_test1();
extern 'MyDll2.dll' float my_test2();
extern 'MyDll2.dll' LPCWSTR my_test3();
k1: my_test1;
k2: my_test2;
comment(my_test3);
若要返回序列或数组,则把需要返回的序列赋值目标当作参数传递给DLL,在DLL内部直接修改已达到赋值。注意逐根运行模式下,每一根K线都会调用dll,所以通常每次调用只需要赋值比上一根K线新增加的类型,例如计算收盘价均值时,每次在BarPos位置填入当根K线的均值即可。由此可见,这种应用下通常需要把 BarPos(当前是第几根K线)作为参数传入Dll中。
返回序列和数组的例子
extern "C" __declspec(dllexport) void WINAPI my_test4(float*pReturn, int nIndex)
{
   pReturn[nIndex-1] = 123;
}
extern "C" __declspec(dllexport) void WINAPI my_test5(float*pReturn, int nLen)
{
   for(int i=0;i<nLen;i++)
         pReturn = 0;
}
相应的公式调用例子
#MAINCHART
#Run_By_Bar
variable:
  NumericSeries mySequence(0);
array:
  myArray[100](1);
extern 'MyDll2.dll' void my_test4(NumericSeries mySequence, int nIndex);
extern 'MyDll2.dll' void my_test5(NumericArray myArray, int nLen);
my_test4(mySequence, BarPos);
my_test5(myArray, 100);
(四)DLL的参数类型

-

单值

序列

数组

引用

数值

NumericSimple

NumericSeries

NumericArray

NumericRef

字符串

String

序列

StringArray

StringRef

(五)无效数据表示
公式系统使用std的无效浮点数表示无效值,浮点无效值的一个重要特征是 f != f 为真,可作为判断依据,其它运算皆输出无效值,其它比较皆输出假。当序列作为指标输出时,开始和结束两段的无效值自动截除,不作为指标输出。例如要输出5日均线,序列的前4个值可填充无效值(填充0时会使指标线变形)
#include <limits>
#define INVALID_NUMERIC std::numeric_limits<float>::quiet_NaN()
无效值在公式里可以用 Invalid 关键字指定,例如
k1:Invalid;
k1指标线不会输出
三、系统 DLL调用
调用win32提供的系统DLL,与调用自己编写的DLL是一样的。
只要知道windows系统函数所属的DLL和函数名,参数等信息就可以直接使用,例如
extern 'kernel32.dll' int GetTickCount();
tickcount:GetTickCount();
同样地,这种用法只能工作于逐根模式下。
    四、.NET DLL调用
只能在逐根模式中使用.net DLL
跟一般DLL不同的是,.net DLL在声明时,除了函数名信息,还要提供命名空间、类名的信息,例如:
extern 'RzRq.dll' void RzRq.Grabber.GetFinance( LPCWSTR stockCode);
这里的RzRq就是命名空间,而Grabber则是类的名称,GetFinance是函数名。

使用道具 举报

Rank: 2

发表于 2013-8-30 20:48:21 |显示全部楼层
hslixuexue 发表于 2013-8-30 17:30
(十)开发DLL的详细例子
这里例子是使用VS2012制作的。
1. 首先创建Win32的工程项目,项目名称是MyDll

楼主强大啊,期待继续

使用道具 举报

Rank: 3Rank: 3

发表于 2013-8-31 09:36:32 |显示全部楼层
leon1 发表于 2013-8-30 20:48
楼主强大啊,期待继续

不好意思,我只是整理加理解。

使用道具 举报

Rank: 3Rank: 3

发表于 2013-8-31 19:12:43 |显示全部楼层
本帖最后由 hslixuexue 于 2013-8-31 19:15 编辑

五十五、简单策略逐行解读一

如何上手,不可能开始用资金去搞吧。策略的构思不在本教程之列,用现成的策略,从操作上讲,已经学会了。因此重要的问题就是提高编程能力。解读一些常见的策略,来提高编程水平。

日内交易之开盘区间突破

日内交易常用的一类策略是开盘区间突破,它与通道突破策略相似。该策略以当日开盘价加减由Rng参数指定的范围,形成一个区间,当价格突破区间时进场交易,收盘时清仓不过夜。其基本公式是:
   //-------智能交易公式--------------
   //3_1 开盘区间突破策略
   //用于分钟线周期
   {策略描述:
   1.当日开盘价加减指定价差形成区间
   2.突破区间高点做多,跌破区间低点做空
   3.当天仅做多1次,做空1
   4.日内交易,收盘前清仓
   }
   input: //自定义参数设置
     Rng(10), //参数,浮动范围点数
     EndTime(1400); //内置函数设参数?结束时间定14:00
   RngH: OpenD(0) + Rng; // RngH指标线。上限价格:当日开盘价加幅度,主图上每日显示一条线段。
   RngL: OpenD(0) - Rng;// RngL指标线。下限价格:当日开盘价减幅度,主图上每日显示一条线段。
   if Time < EndTime*100 then begin//下午14:00前开始
    if EntriesToday(Date,MP_LONG)<1 then//开多仓次数<1
       Buy(, 2, RngH, -1, OT_STOP); //超过上限2手追价单
     if ExitsToday(Date,MP_SHORT)<1 then //开空次数<1
   SellShort(, 2, RngL, -1, OT_STOP); //超过下限2手追价单
   end;
   SetExitOnClose; //收市时清仓
   {注解:

  1.OpenD(0)返回当日开盘价,这套函数在日内交易时方便常用;

  2.EntriesToday(Date,MP_LONG)取得自己当天多头开仓次数,MP_LONG是值为1的宏;

  3.ExitsToday (Date,MP_SHORT)取得当天开空仓次数,MP_SHORT是值为-1的宏;

  4.SetExitOnClose用于在收市时清仓,历史测评时以收盘价作为平仓价,自动交易时在收市前若干秒平仓,

可在【策略设置】中设置,默认在收市前60秒清仓。   }

上例的区间范围Rng是个常数,不能适应市场变动,所以Rng通常用各种算法得到,例如,

著名的Dual Thrust系统曾长期在交易系统排行榜名列三甲,其原始公式应用于日线周期,不太能如实反映日内波动,把它改造为应用于分钟周期的策略:
   //-------智能交易公式--------------
   //用于1分钟-15分钟周期
   {策略:
   1.根据前几日的波动范围动态调整开盘区间,用不同的参数分别设置买卖区间的幅度。
   2.突破区间高点做多,跌破区间低点做空
   3.可选是否持仓过夜}
   input: //参数设置   K1(0.5),K2(0.5),Mday(1),Nday(1),
     ExitOnClose(1); //外部参数控制是否做日内交易或持仓过夜
   variable:
    BarsPerDay(48), BuyRange(1000),SellRange(1000); //变量,此处初始值没有意义,但是需要设
   if BarPos = 1 then begin  //第一根有效K线开始,只是一个启动标志。只有一次成立,故只能计算一次。
     switch DataPeriod begin//沪深300股指期货日周期数
      case 1: BarsPerDay:=270; // BarsPerDay变量为1天的K线数量,只需在第1K线时计算1次, 1分钟周期,赋值270,仅针对股指期货,下同。
       case 2: BarsPerDay:=54;  //5分钟周期,赋值
       case 3: BarsPerDay:=18; //15分钟周期,赋值
     end
   end
   Bars:= Mday*BarsPerDay; //选择K线数,Mday默认1
   MHH := HHV(H,Bars)[1]; // [1]序列变量HHV下标,前一周期HHV(H,Bars)值。可以把:=改为:进行调试,即中间变量变指标,图形显示。通过调试发现出现1天内有不同MHH值,说明本指标是逐根计算的,不是只计算一次,不是昨日最高价。前一周期Bars 周期内BAR线最高价的最高值。下同。
   MHC := HHV(C,Bars)[1]; // 前一周期Bars 周期内BAR线收盘价的最高值
   MLL := LLV(L,Bars)[1]; //
   MLC := LLV(C,Bars)[1]; //
   Bars:= Nday*BarsPerDay; // 如果NdayMday取值一样,则下面值一样。Nday默认1天。
   NHH := HHV(H,Bars)[1]; //
   NHC := HHV(C,Bars)[1]; //
   NLL := LLV(L,Bars)[1]; //
   NLC := LLV(C,Bars)[1]; //
    if Date <> Date[1] thenbegin  //新交易日开始,计算区间范围,Date <> Date[1],是指确定起点、交界点。
    BuyRange := Max(MHH - MLC, MHC -MLL);

    SellRange := Max(NHH - NLC, NHC -NLL);

   end
   RngH: OpenD(0) + K1*BuyRange; //计算上限,并作为指标线输出。
   RngL: OpenD(0) - K2*SellRange; //  
   if SessionLastBar = 0 then begin//是否当日最后一个周期,SessionLastBar用法与字典解释,无法衔接:当日、当前时段。

     Buy(, DEFAULT, RngH, -1,OT_STOP,OB_NEXTBAR);

     SellShort(,DEFAULT, RngL, -1,OT_STOP,OB_NEXTBAR);

   end
   if ExitOnClose then SetExitOnClose; //ExitOnClose参数控制是否收市平仓。输入为1,是。


使用道具 举报

Rank: 3Rank: 3

发表于 2013-9-1 00:03:22 |显示全部楼层
本帖最后由 hslixuexue 于 2013-9-1 00:05 编辑

五十六、简单策略逐行解读二

分批开平仓

分批开平仓不仅要求可以根据不同的信号连续进场,然后对分次开出的仓位分别控制,另外,用不同的止盈目标位分批出场也是常用的技巧,我们来看一个实例,公式如下:
   //-------智能交易公式--------------
   {策略:
   1.允许连续买入2
   2.突破20周期高点买入1次,该仓位命名为'Buy1'
   3.突破50周期高点买入1次,该仓位命名为'Buy2'
   4.跌破10周期低点卖出'Buy1'的仓位
   5.跌破25周期低点卖出'Buy2'的仓位
   }
   Buy1: HHV(H,20),Shift1;//突破20周期移动高点,逐根模式下,未来的BAR过程中是没有HHV的,Buy1+MinDiff无法运行的。因此需要把当前值右移给下一根BAR,当然也许可以用其他方法实现,比如能否用refBuy11)?
   Buy2: HHV(H,50),Shift1; //突破50周期移动高点,右移
   Sell1: LLV(L,10),Shift1; //跌破10周期移动低点,右移
   Sell2: LLV(L,25),Shift1; //跌破25周期移动低点,右移
   AllowSameEntries(2); //允许连续同向开仓次数,右移
   //if EntryName <> 'Buy1' then{本行只是注释。可以用函数EntryName识别已有哪个信号的仓位。但是即使允许连续同向开仓,也不允许连续开相同开仓名的仓,所以本句可以不用}

Buy(,1,Buy1+MinDiff,-1,OT_STOP,OB_NEXTBAR,'Buy1');// MinDiff为价格最小变动单位

  //if EntryName <> 'Buy2'then{本行只是注释。}

    Buy(,1,Buy2+MinDiff,-1,OT_STOP,OB_NEXTBAR,'Buy2');

   Sell(,1,Sell1,-1,OT_STOP,OB_NEXTBAR,'Sell1')from 'Buy1'; //平仓指令函数后用from指定平掉哪个开仓信号的仓位,达到Sell1与Buy1、Sell2与Buy2分别一一配对,这样我们就可分别控制不同的仓位。

   Sell(,1,Sell2,-1,OT_STOP,OB_NEXTBAR,'Sell2')from 'Buy2';



     再看一个早盘区间突破分批平仓日内交易策略,公式如下:

//-------智能交易公式--------------
//用于5分钟周期
{策略:
1.根据上午10点前的价格波动范围画出最高价水平线
2.下午14点前,价格突破区间高点买入2
3.跌破买入价以下20点清仓止损
4.涨至买入价以上30点止盈其中1
5.当天若有亏损交易,不再开新仓
6.日内交易,收市前清仓 }
input: //参数声明
早盘终点时间(1000), //自定义参数10:00
开仓结束时间(1400); //自定义参数14:00
variable: //变量声明
ID(-1);  //变量趋势线标识号,赋初值-1

if Date <> Date[1] thenbegin  //新交易日开始

RngH := High; //中间变量

ID :=TL_new(Date,Time,RngH,Date,Time,RngH); //新建画线,TL_new()逻辑值是IDTL_new()参数可以前后表达一样,理想中在只产生一个点的世界中可以以该点为起点和终点画一条线。这个不成有过的概念

end
if Time < 早盘终点时间*100 then begin //上午10:00前,*100Time格式还有2位数的秒钟。
RngH := Max(High, RngH); //获取区间最高点价格,每个周期的最高价与过去最高价的最高价进行比较取最高价。
end
//随时间动态调整区间高点水平线

TL_SetBegin(ID,TL_GetBeginDate(ID),TL_GetBeginTime(ID), RngH); //起点在区间高点

TL_SetEnd(ID, Date, Time, RngH);//终点:时间、日期在当前,价格在区间高度。

bTradeTime := Time >=0955*100 And Time < 开仓结束时间*100;// bTradeTime中间变量,交易时间。时间在9点55到14点之间。5分钟周期,9:55的下一个周期开始交易

if bTradeTime AndDailyLosers(Date,0)<1 then //时间符合,且当日日亏损次数小于一

Buy(, 2, RngH, -1, OT_STOP,OB_NEXTBAR, '买入'); //突破买入

if MarketPosition = 1 then  begin //若持仓状态多头,检查所有多头

Sell(, DEFAULT, EntryPrice - 20,-1, OT_STOP, OB_NEXTBAR, '止损'); //跌破买入价以下20点清仓止损

if CurrentContracts = 2 then //持仓数量= 2

Sell(, 1, EntryPrice + 30, 0,OT_LIMIT, OB_NEXTBAR, '止盈'); //涨至买入价以上30点止盈其中1口  

   end
   SetExitOnClose; //收市前清仓
从这个公式,我们可以看出它逐根计算的机制:在每天开盘的那根K线创建1条新的趋势线,然后随着下1K线的不断增加,调整趋势线的起点和终点。

使用道具 举报

Rank: 4

勇士奖

发表于 2013-9-14 10:12:16 |显示全部楼层
感谢楼主的无私奉献,功德无量~本来自己也想总结一个,可惜人太懒,只好享用现成的了。

使用道具 举报

Rank: 2

发表于 2013-9-14 19:02:48 |显示全部楼层
太好了,谢谢。继续完善。。。。。。期待。。。。。

使用道具 举报

Rank: 3Rank: 3

发表于 2013-9-26 00:06:38 |显示全部楼层
本帖最后由 hslixuexue 于 2013-9-26 00:55 编辑

五十七、简单策略逐行解读三

指标背离交易及风险控制策略

缠论等交易理论重视指标背离时的交易信号,请看如何实现:
//-------智能交易公式--------------
{策略:
RSI指标上穿25且与价格形成底背离时买入,不采用指标平仓,而是综合运用止盈、止损、保本平仓、跟踪止损、盘整平仓等风险控制技术}
input: //参数设置
     波谷强度(3),//用于找波谷并判断背离,波谷点是前后各N个周期的相对低点,这个N即为波谷强度
     止损价差(35),
     止赢价差(100),
     保本启动价差(20),
     跟踪启动价差(30),
     跟踪回撤价差(20),
     跟踪回撤幅度(20),
     盘整最大价差(5),
     盘整周期数(5),
     使用价差(1), //开关控制使用价差或金额参数
     止损金额(10000),
     止赢金额(30000),
     保本启动金额(6000),
     跟踪启动金额(9000),
     跟踪回撤金额(6000);
       RSI1 :SMA(Max(C-C[1],0),8,1)/SMA(Abs(C-C[1]),8,1)*100,OwnerScale; //计算RSI指标公式:RSI=100×RS/(1+RS) ,RS=X天的平均上涨点数/X天的平均下跌点数。RSI=100×X天的平均上涨点数/(X天的平均上涨点数+X天的平均下跌点数)。Max(C-C[1],0) X天上涨点数。X天的平均上涨点数SMA(Max(C-C[1],0),8,1)。SMA(Abs(C-C[1]),8,1)*100指(X天的平均上涨点数+X天的平均下跌点数)。OwnerScale修饰符可以使RSI指标叠加在主图上。
底背离: Divergence(C,RSI1,波谷强度,30,-1), LineThick0; //LineThick0修饰符用于查看底背离状态而不画出指标线
if 底背离 and CrossOver(RSI1,25) then Buy; //若指标与价格走势发生牛背离,则在指标上穿25时买入
if 使用价差 = 1 then begin //单独一行,end结束
SetStopContract;  //参数控制以下风控金额基于单口计算。每个仓位都会执行下列公式。
   if 止损价差 > 0 then SetStopLoss(止损价差*BigPointValue);
   if 止赢价差 > 0 then SetProfitTarget(止赢价差*BigPointValue);
   if 保本启动价差 > 0 then SetBreakEven(保本启动价差*BigPointValue);    if 跟踪启动价差 > 0 And 跟踪回撤价差> 0 then       SetDollarTrailing(跟踪回撤价差*BigPointValue,跟踪启动价差*BigPointValue);
    if 跟踪启动价差 > 0 And 跟踪回撤幅度> 0 then       SetPercentTrailing(跟踪启动价差*BigPointValue,跟踪回撤幅度);
    if 盘整最大价差 > 0 And 盘整周期数> 0 then      SetInactive(盘整最大价差*BigPointValue,盘整周期数);
end
   else begin
     SetStopPosition;  //整个仓位的止损止盈金额
     if 止损金额 > 0 then
       SetStopLoss(止损金额);
     if 止赢金额 > 0 then
       SetProfitTarget(止赢金额);
     if 保本启动金额 > 0 then
       SetBreakEven(保本启动金额);         if 跟踪启动金额 > 0 And 跟踪回撤金额> 0 then
       SetDollarTrailing(跟踪回撤金额,跟踪启动金额);
        if 跟踪启动金额 > 0 And 跟踪回撤幅度> 0 then
       SetPercentTrailing(跟踪启动金额,跟踪回撤幅度);
   end




使用道具 举报

Rank: 3Rank: 3

发表于 2013-9-26 00:11:41 |显示全部楼层
本帖最后由 hslixuexue 于 2013-9-26 00:59 编辑

五十八、简单策略逐行解读四

自动趋势线交易策略

之前介绍过画水平线,还可以通过波峰、波谷点函数自动画出趋势线并据此交易,让我们看看这个公式:
//-------智能交易公式--------------
//用于5分钟周期
{策略:
1.在当天5分钟周期走势上自动画出下降趋势线(波峰上的趋势线,前提认定大趋势为下降趋势。)
2.突破下降趋势线买入
3.当最大浮盈达到10点后,把盈利锁定在买入价之上1
4.当最大浮盈达到20点后,把盈利锁定在买入价之上8
5.当最大浮盈达到30点后,把盈利锁定在买入价之上10
6.买入价之上50点为止盈位,买入价之下10点为止损位}
input:     波峰强度(3); //找出最近M个波峰点,每个波峰点的H大于前后各N个周期的H,这个N即为波峰强度。M为趋势线考察范围。
    const:点数量(5); // const常数声明
    array: 波峰点日期[点数量](0),波峰点时间[点数量](0),波峰点数值[点数量](0); // 数组声明。[点数量]元素下标最大值,(0)初始值。每个数组数据个数是[点数量] +1 =5+1。即6个波峰上的数据。但是这六个不是固定的,随着时间推移,新的波峰产生一个,最早的那个就排除在外。如第7个产生,则第1个不再M内了。[0]不是第一个,而是最后一个、最新的一个    variable:下降线ID(-1), 起点下标(0); //变量声明
    if Date<> Date[1] then begin //新交易日开始时重新找趋势线
    //print('=======',Date, '=======');{ print函数输出分隔线、日期到[公式日志],可用于调试公式,可选语句}

下降线ID:= -1;
    for pos=0 to点数量 dobegin//依次赋值下标以读取数组元素
波峰点日期[pos]:=0; //清空数组内每一个数据并赋值为0
波峰点时间[pos]:=0;
波峰点数值[pos]:=0;
end
end
位置:SwingHighBar(1,High,波峰强度,波峰强度+1),linethick0; // SwingHighBar返回最近一个波峰点距当前周期数。linethick0不显示。
if 位置=波峰强度 then begin //出现的最新最近一个波峰点。
if Date[位置] = Date And Time[位置] <> 波峰点时间[0] then begin//新波峰日期与当前日期相同,新波峰时间最近波峰不同,判断该波峰点是当天的且没被记录过。
//print('时间:', Time/100, '  波峰强度: ', 波峰强度); {可选}
   for pos = 点数量-1 DownTo 0 do begin//循环语句
       波峰点日期[pos+1] := 波峰点日期[pos]; //降循环,原来最后一个舍去,把倒数第二个作为最后一个,倒数第三个作为倒数第二个,,把新的作为第一个。
       波峰点时间[pos+1] := 波峰点时间[pos];
       波峰点数值[pos+1] := 波峰点数值[pos];
     end
     //将新波峰点存入数组下标0的位置
     波峰点日期[0] := Date[波峰强度]; //第一个波峰日期
     波峰点时间[0] := Time[波峰强度]; //第一个波峰时间
     波峰点数值[0] := High[波峰强度]; ////第一个波峰价格
//print('时间:', 波峰点时间[0]/100,'  数值:', 波峰点数值[0]);
    ifMarketPosition <1 then begin //如果未持多仓,如果持多仓,表示看涨,则画下降趋势线无意义
//更新趋势线,找趋势线起点,起点应比最近的新波峰点高,才能形成下降趋势线
    for pos= 1 to 点数量 do begin
if波峰点数值[pos]> 波峰点数值[0] then  begin//有比新波峰更高的。这个动态趋势线实质:并不是最近6个波峰选出的趋势线,而是新波峰与最近一个高于新波峰的点之间的趋势线。
起点下标 := pos;

pos :=点数量+1;  //For语句中再加1,然后跳出循环

      end

       end

if pos<> 点数量+1  then begin //表示找到有更高的波峰点

//print('TL_SetBegin:',波峰点时间[起点下标]/100,'  数值:', 波峰点数值[起点下标]);{可选}

//print('TL_SetEnd :', 波峰点时间[0]/100,'  数值:', 波峰点数值[0]); {可选}

//if 下降线ID = -1 then{可选}

下降线ID :=TL_New(Date,Time,High,Date,Time,High); //动态趋势线起点终点都是一样的,一步一步设立起点和终点。TL_New逻辑值是趋势线id(可以赋值给其他变量),变量下降线ID不再是-1。

TL_SetBegin(下降线ID, 波峰点日期[起点下标],波峰点时间[起点下标],波峰点数值[起点下标]);
TL_SetEnd(下降线ID, 波峰点日期[0],波峰点时间[0],波峰点数值[0]);
       end//有一个begin,就在下面另行写end,以免遗漏
     end
   end  
   end

elsebegin//第二个if如果有新的波峰出现,否则。如果有else,应该在书写if时隔行书写以免混淆

TL_SetEnd(下降线ID,Date,Time,TL_GetValue(下降线ID,Date,Time)); //起点、终点在上一轮满足条件的时候已经赋值,如果这一轮不满足条件,不修改起点值,修改终点值。终点值为原趋势线延伸在当前时间的价格。实际上趋势线没变。目的是延伸趋势线到当前时间
   end//第二个if  begin
TLValue:=TL_GetValue(下降线ID,Date,Time); //当前趋势线上价格

bEnterLong :=CrossOver(C, TLValue); //穿越趋势线

if Time< 143000 And 下降线ID > -1 And bEnterLong thenBuy; //下降线ID > -1防止没有趋势线时程序混乱。Buy,参数?

ifMarketPosition>0 then begin  //持有多头仓位

Sell(,DEFAULT, EntryPrice+50, 0, OT_LIMIT, OB_NEXTBAR, '止盈'); //价格止盈

Sell(,DEFAULT, EntryPrice-10, -1, OT_STOP, OB_NEXTBAR, '止损'); //价格止损

ifMaxContractProfit>10*BigPointValue then//价格止盈与浮盈针对不同品种,浮盈主要指股指期货。

Sell(,DEFAULT, EntryPrice+1, -1, OT_STOP, OB_NEXTBAR, '锁盈1'); //

ifMaxContractProfit>20*BigPointValue then

Sell(,DEFAULT, EntryPrice+8, -1, OT_STOP, OB_NEXTBAR, '锁盈2');

ifMaxContractProfit>30*BigPointValue then

Sell(,DEFAULT,EntryPrice+10,-1, OT_STOP, OB_NEXTBAR, '锁盈3');

end
SetExitOnClose;
这个公式比较复杂,本ID在编写时用print函数在一些重要位置输出(到【公式日志】,可在【量化交易】主菜单下打开)、观察数据进行调试,调试通过后再把print语句注释掉。
各位可以试着把本公式中的print语句前的注释去掉,运行公式,看看【公式日志】,有助于理解公式逐根执行的逻辑,提升调试技巧。




使用道具 举报

Rank: 3Rank: 3

发表于 2013-9-26 00:14:47 |显示全部楼层
本帖最后由 hslixuexue 于 2013-9-26 01:02 编辑

五十九、简单策略逐行解读五

网格交易和鞅加仓策略

网格交易法在振荡行情中用得较多,设想一个最简单的网格交易策略,公式如下:
//-------智能交易公式--------------
//用于分钟周期
{策略:
1.日内交易,预计行情震荡且偏多
2.起始价位上限,起始价为不算网格,其下不设单,价格往下回落网格间距设第一条网格,依次设网格,第一条网格下开始设单。总单数为网格总数。随着价格的暂时回落,将会逐渐挂满单。
3.每笔买入以网格间距止盈,盈利目标位与网格间距相同
4.日内交易,收市前清仓,在振荡行情下,这样的策略可以频繁地小赚。}
   input: //参数声明
     起始价位(2250), 网格总数(10), 网格间距(3);
   variable: //变量声明
     BuyName(), SellName();//声明为字符串变量
   AllowSameEntries(网格总数); //允许连续买入次数       if MarketPosition = 0 andNot(SessionLastBar) then begin //无仓且不是最后bar
    Buy(,1,起始价位-网格间距,0,OT_LIMIT,OB_NEXTBAR, '买1'); //开多,从上到下,第一格

   end
   else if MarketPosition = 1 then begin //已经存在多仓
     if Not(SessionLastBar) then begin//不是最后bar
       for n=CurrentEntries to 网格总数-1 do begin//计算当前开仓总次数,循环到网格总数-1。虚盘不会符合条件不成交,当前持仓之后开仓,保证不会在同一格内重复开仓。CurrentEntries为当前持仓的开仓次数,已平掉的不在内。
         BuyName:= ''+NumToStr(n+1,0); // BuyName中间变量,值在新的值产生后以前值不保存。为设定的每个剩余网格取买单名,并赋值中间变量。字符运算,数字转化为字符串
    Buy(,1, EntryPrice-n*网格间距,0,OT_LIMIT, OB_NEXTBAR, BuyName);//当前开仓价格之下,每格挂买单。若持仓中已有同名仓位,不会连续开仓。
       end//每次新的bar产生时,会重复以上的取名、挂单,因为如果卖单成交,就必须重新取名。
     end //两个连续条件,中间无间隔,可以一个ifand

forn=CurrentEntries downto 1 do begin //又见降循环,检查价格反弹,每bar执行。

       BuyName:= ''+NumToStr(n,0); //指定买单名重新赋值中间变量,使中间变量针对当前单之前单赋值。
       SellName := ''+NumToStr(n,0); //设置卖单名,赋值中间变量,供引用。
    sell(,1,EntryPrice-(n-2)*网格间距,0,OT_LIMIT, OB_NEXTBAR,SellName) from BuyName; //指定买单,价格反弹一格以上挂卖单。由于是限价卖单,实盘交易不可能跳过顺序成交?
     end
   end
   SetExitOnClose;
网格交易还可配合鞅(Martingale)加仓策略。
鞅(Martingale)加仓策略:初次买入后,若价格下跌,则分批加仓买入,当价格稍有反弹,整个仓位即可盈利出场。
//-------智能交易公式网格交易鞅加仓策略--------
//用于分钟周期
{策略:
1.找个有利位置买入开仓,例如CCI指标小于-200
2.若价格相对上次开仓价格下跌了某个价差,根据加仓系数进行马丁格尔加仓;
3.整个仓位按指定金额止盈;
4.对整个仓位按指定金额止损,控制风险。}
input:
  网格总数(10), 网格间距(6),
  初次单量(10), 加仓系数(1.2),
  盈利点数(6), 止损金额(20000);
variable:
  BuyName();
  AllowSameEntries(网格总数); //允许连续买入次数
//计算CCI指标

TYP :=(H + L + C)/3;

CCI1:=(TYP-MA(TYP,14))/(0.015*AveDev(TYP,14));

BuyName :='买1';

if CCI1< -200 and MarketPosition = 0 then

Buy(, 初次单量,0,0,OT_Market,OB_NEXTBAR,BuyName);

ifMarketPosition = 1 then begin

for n=2to 网格总数 do begin

BuyName :='买'+NumToStr(n,0);

Buy(,Round(初次单量*Pow(1.2,n-1)), LASTENTRYPRICE-网格间距*(n-1),0,OT_LIMIT,OB_NEXTBAR,BuyName);

end
end

SetStopPosition;//设定止盈止损金额以整个仓位计算,可以省略,因为整个仓位,所以就不需设置sell单。

SetProfitTarget(盈利点数*BigPointValue*初次单量);

SetStopLoss(止损金额);

以上2个例子的网格交易是越跌越买的,也可反向操作,越涨越买,再配合仓位控制、多空双向交易。




使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

bottom

Archiver|http://www.patiosoft.com

GMT+8, 2017-12-16 04:05 , Processed in 0.116593 second(s), 9 queries .

花生网 Copyrigh©2012

和讯信息科技有限公司 ALL Rights Reserved 版权所有 复制必究

回顶部