外汇自动交易实盘
非常有用的一篇文章,关于如何在高频自动交易中Preventing Repeat Orders and Whipsaws,几个思路典型而广泛适用,
在这篇文章的帮助下较好地解决了重复发单问题
https://www.amibroker.org/userkb/2007/07/14/preventing-repeat-orders-and-whipsaws/
201027
这个月前一段对行情有些期待,后来么想想不用做什么,也就没怎么看了,在捣鼓我的自动交易小机器人.
看,界面就是这样拉,vba做不下去了,还是回AB来….
背景颜色根据持仓方向变化.上面一排按钮,绿的是几个信息,灰的是几个手动开关,点了还有语音提示,比如“~Auto Trade
Start”
本地只管发单,不管后续控制.TICK级别入场,满足买卖条件并处于空仓状态时,就发送包围单,一张市价\一张限价止赢\一张限价止损.
不会由于时延和价格反复而重复发单,不会由于网络错误而风险失控.
经过着几天调试,几乎接近可用的状态了.准备周末找历史数据测试几个策略\确定一下参数和交易频率,下周可能就可以挂起来了.
一个新的1W刀的IB帐户和一个租了半年的VPS已经提前准备好了.
目前还是玩玩的心态,实践里再摸索吧,暂时也没什么盈亏的期望,只要能把想做的做到就很开心了
201004
自动交易这个礼拜开始挂机,技术实施上面就不多说,关于交易策略,我有了点新的认识.
根据本贴一楼的思想,我的实盘交易策略是
bid-ma(c,108)>40,卖出,挂20点的止损,10点的止赢
ma(c,108)-ask>40,买入,挂20点的止损,10点的止赢
这里赢损并不相等等,但是基础假设和前文是一致的,认为等幅赢损的触发概率是一样的.
经过实践发现这种策略存在严重缺陷,主要在成交滑点上.下图是某段时间的各笔交易赢亏
图中两比交易止损大大超过预算(40),下图是这两比交易完成的细节和当时行情(联储公布重要事项)
卖出交易的条件是bid-ma>40,市价单的理论成交价格是bid,事实上价格快速波动时成交价格会在bid左右的一个范围内。
根据分析成交数据,图中第一单系统出信号时bid为1.4084,这个是理论成交价,可是实际成交价格为1.410089,超16个点,因该说这是好的,这样卖到了更高的价格了,但是止损是按1.4084+20点设置的,因此卖出后瞬间(1秒)触发了止损条件,进行买入操作,可实际上买入止损单成交在1.4130,比报价位置1.4084+20=1.4104高了26个点。实际多损失26点。(如果卖出价格高而止损价格维持,则会出现小额止损的情况。)
第二笔交易市价卖出单比理论低了9个点,止损单比理论高了31个点。实际多损失40个点。
偏离均线反趋势交易在统计上很好理解,也很有优势,但是在实际执行中困难重重,事实上,大幅偏离均线的时候,往往是波动极大,成交及其没有保证的时候。因此选择这种时候作为“存在优势的点“而交易是先天不足的,因为不能很好的保证成交,所以这个策略不是该理念的一种合适的实施.
这个策略这几天交易上百笔,亏了$366,交易手续费是2.5/笔,既然发现了问题(和特定行情无关的问题),那就不打算继续使用了.
我认为应该选择同时满足这样两个条件的位置去开随机单(赢损等幅):1市场波动性不大,2存在某种概率优势.
照这两条又想了一个策略:取两根均线L和S,L长期,S短期,P表示价格
S>P>L,买入,挂等幅赢损
S<P<L卖出,挂等幅赢损
每天定时判断条件并挂单
一方面,认为价格在长期均线上(下)方,做多(空)是有优势的,另一方面,认为价格处于长短期均线中间时波动性是较小的.这样两个条件都满足了.我觉得这样应该能赚钱了,不发现重大问题的话会多挂一段时间,如果稳定亏损(>2个月,>500笔),就说明1楼的想法有问题,那似乎就只能采取本地实时控制的策略了(现在用的是发完单后面就不管的策略)
101115
一周的情况
策略:
c-ma(c,640)>0.0015 大于640周期15点做多
ma(c,640)-c>0.0015 小于640周期15点做空
abs(c-ma(c,20))<0.0020 过滤条件:与20周期偏离小于20点,尽量保证成交在市场波动平缓的区间
定时交易,每个小时的第22分钟判断上面条件,满足就挂15点的等幅赢损单,交易量20000,交易对象eur.usd
上周成交情况:
上周累计盈亏(蓝的是不记手续费,红的是计算手续费的):
具体情况是手续费350,不记手续费的交易赢利169.两个一减是亏的,但是有一点没考虑,就是我现在交易量是一笔20000,手续费2.5,这个2.5/笔是IB的外汇交易最小手续费.eur目前一笔交易交易91250也是2.5,再大的量才超过这个2.5的最小佣金限制.如果我把每次交易20000扩大到91250,那盈亏放大4.5625倍,但是手续费是不变的,还是有可能赢利的.
假设交易量放大4.5625倍时上周的累计盈亏(蓝的是不记手续费,红的是计算手续费的)
101122: 两周后的情况
程序如下:
_SECTION_BEGIN(“Price”);
#include
<ControlPanelInclude-001.afl>
global ColNumber;
RequestTimedRefresh( 1 );
NewSecond = Status(“redrawaction”);
ibc = GetTradingInterface(“IB”);
if(GetRTData(“Bid”)){
EnableTextOutput( False );
Title=””;
CellHeight = Param(“Cell Height”,10,3,100,1);
CellWidth = Param(“Cell Width”,120,5,200,1);
PanelYoffset = Param(“Cell Row Offset
(px)”,10,0,Status(“pxheight”),1);
PanelXoffset = Param(“Cell Column Offset
(px)”,10,0,Status(“pxwidth”),1);
FontRatio = Param(“Font: CellHeight ratio”,2,1,20,0.1);
ClickCoordinates = Nz(StaticVarGet(“ClickCoordinates”));
sAutoTrading = Nz( StaticVarGet( “AutoTrading” ) );
ATonTrigger = ParamTrigger( “Start AutoTrading”, “START” );
AToffTrigger = ParamTrigger( “Stop AutoTrading”, “STOP” );
BuyLockoutPeriod = Param(“BuyLockoutPeriod”,10,1,300,1);
SellLockoutPeriod = Param(“SellLockoutPeriod”,10,1,300,1);
Reset = ParamTrigger(“Reset All”,”RESET”);
BuyOrderID = StaticVarGetText(“BuyOrderID”);
SellOrderID = StaticVarGetText(“SellOrderID”);
BuyOrderIDLMT = StaticVarGetText(“BuyOrderIDLMT”);
BuyOrderIDSTP = StaticVarGetText(“BuyOrderIDSTP”);
SellOrderIDLMT = StaticVarGetText(“SellOrderIDLMT”);
SellOrderIDSTP = StaticVarGetText(“SellOrderIDSTP”);
ibc = GetTradingInterface(“IB”);
ConnectedStatus=ibc.IsConnected();
BuyPending = ibc.IsOrderPending(BuyOrderID);
BuyLMTPending= ibc.IsOrderPending(BuyOrderIDLMT);
BuySTPPending=
ibc.IsOrderPending(BuyOrderIDSTP);
SellPending = ibc.IsOrderPending(SellOrderID);
SellLMTPending= ibc.IsOrderPending(SellOrderIDLMT);
SellSTPPending=
ibc.IsOrderPending(SellOrderIDSTP);
Avgcost=ibc.GetPositionInfo( Name(), “Avg. Cost” );
Tol=ibc.Getaccountvalue(“CashBalance”);
Column_Begin( “1” );
zero=IIf(C>0,0,1);
zero1=Cum(zero);
printf(“\nzero:”+zero1+”\n”);
TextCell(“ATS:”+WriteIf(
(StaticVarGet( “sAutoTrading” ) AND (ConnectedStatus==2 OR
ConnectedStatus == 3 ) AND Nz
(GetRTData(“Bid”),0) ),”ON”,”OFF”),
colorBrightGreen, colorBlack);
Column_End( );
Column_Begin( “3” );
Reset = TriggerCell( “START”, 3, colorRed, colorBlack);
Column_End( );
Column_Begin( “4” );
CancelAll = TriggerCell( “CANCEL”, 3, colorRed, colorBlack);
Column_End( );
Column_Begin( “5” );
CloseAll = TriggerCell( “CLOSE”, 3, colorRed, colorBlack);
Column_End( );
Column_Begin( “6”);
EndSession = TriggerCell( “END”,3, colorRed, colorBlack);
Column_End( );
Column_Begin( “7” );
TextCell(“Hold:”+ibc.GetPositionSize( Name() ), colorBrightGreen,
colorBlack);
Column_End( );
Column_Begin( “8” );
TextCell(“PnL:”+WriteIf(
Name() )>0
,””+Nz(int((GetRTData(“bid”)-Avgcost)*ibc.GetPositionSize(
Name()
))),””+Nz(-int((Avgcost-GetRTData(“ask”))*ibc.GetPositionSize(
Name() ) ))
colorBlack);
Column_End( );
Column_Begin( “9” );
TextCell(“Tol:”+StrLeft(Tol,7) ,colorBrightGreen,
colorBlack);
Column_End( );
switch( ClickCoordinates )
1 );
Orders”);
ibc.CancelAllPendingOrders();
Positions”);
ibc.CloseAllOpenPositions();
ibc.CancelAllPendingOrders();
ibc.CloseAllOpenPositions();
0 );
printf(
“BuyLMT:”+ibc.GetStatus(BuyOrderIDLMT, True )+
“\nBuySTP:”+ibc.GetStatus(BuyOrderIDSTP, True )+
“\nSELLLMT:”+ibc.GetStatus(SellOrderIDLMT, True )+
“\nSELLSTP:”+ibc.GetStatus(SellOrderIDSTP, True )+
“\n”);
if(ibc.GetPositionSize( Name()
)>0)SetChartBkColor(colorRed);
if(ibc.GetPositionSize( Name()
)<0)SetChartBkColor(colorGreen);
if ( ATonTrigger )StaticVarSet( “sAutoTrading”, 1 );
else
if ( AToffTrigger )StaticVarSet( “sAutoTrading”, 0 );
StaticVarSet( “sAutoTrading”, 1 );
if ( StaticVarGet( “sAutoTrading” ) AND (ConnectedStatus==2 OR
ConnectedStatus == 3 ) AND GetRTData(“Bid”)>0
)
{
price=C;
Ll=MA(price,640);
ss=C;
pema=MA(C,108);
Sellbais=(GetRTData(“Bid”)-pema)*10000;
Buy=(price-Ll)>0.0015 AND
abs(C-MA(C,20))<0.0020 AND
(GetRTData(“Bid”)-GetRTData(“ask”))*10000<2 AND
sellbais<200;
Sell=(Ll-price)>0.0015 AND
abs(C-MA(C,20))<0.0020 AND
(GetRTData(“Bid”)-GetRTData(“ask”))*10000<2 AND
sellbais<200;
if((NOT BuySTPPending) OR ( NOT
BuyLMTPending))
{
StaticVarSetText(“BuyOrderIDLMT”,””);
StaticVarSetText(“BuyOrderIDSTP”,””);
}
if((NOT SellSTPPending) OR ( NOT SellLMTPending))
{
StaticVarSetText(“SellOrderIDLMT”,””);
StaticVarSetText(“SellOrderIDSTP”,””);
}
if(SellOrderIDLMT==”” AND SellOrderIDStp==”” AND BuyOrderIDLMT==””
AND BuyOrderIDSTP==””)
LastTradeOver=1;
else
LastTradeOver=0;
if( NewSecond )
{
BuyCountDown = Max( 0, Nz(StaticVarGet(“BuyCountDown”))-1);
StaticVarSet(“BuyCountDown”, BuyCountDown);
if( BuyCountDown == 0 AND NOT BuyPending )
StaticVarSetText(“BuyOrderID”,””);
SellCountDown = Max( 0, Nz(StaticVarGet(“SellCountDown”))-1);
StaticVarSet(“SellCountDown”, SellCountDown);
if( SellCountDown == 0 AND NOT SellPending )
StaticVarSetText(“SellOrderID”,””);
}
BuyCountDown = Nz(StaticVarGet(“BuyCountDown”));
SellCountDown = Nz(StaticVarGet(“SellCountDown”));
timer2Period =
Param(“timer2Period”,60,1,300,1);
if( NewSecond )
{
timer2 = Max( 0, Nz(StaticVarGet(“timer2”))-1);
StaticVarSet(“timer2”, timer2);
}
timer2 = Nz(StaticVarGet(“timer2”));
printf(“\nBuyCountDown:”+BuyCountDown);
if( LastValue(Buy) AND ( BuyOrderID == “” AND BuyCountDown == 0 )
AND ibc.GetPositionSize( Name() )==0 AND LastTradeOver==1)
{
_TRACE(“Trace 2# IF Able
to
Buy:”+(LastValue(Buy) AND ( BuyOrderID == “” AND BuyCountDown == 0
) AND
ibc.GetPositionSize( Name() )==0
LastTradeOver==1));
if(GetRTData(“Bid”)>0.5 AND
int(Now(4)/100)0==22 AND Now(4)0<=30 )
{BuyOrderID = ibc.PlaceOrder(Name(), “Buy”, 95100, “MKT”, 0, 0,
“Day”, False);
BuyOrderIDLMT=ibc.PlaceOrder(Name(), “SELL”, 95100, “LMT”,
GetRTData(“ask”)+0.00150, 0, “GTC”, False,1,””,BuyOrderID);
BuyOrderIDSTP=ibc.PlaceOrder(Name(), “SELL”, 95100, “STP”,
0,GetRTData(“ask”)-0.00150, “GTC”, True,1,””,BuyOrderID);
AlertIf(1,
TRADE”+”xx”+Tol,Now(4));
StaticVarSetText(“BuyOrderID”,BuyOrderID);
StaticVarSetText(“BuyOrderIDLMT”,BuyOrderIDLMT);
StaticVarSetText(“BuyOrderIDSTP”,BuyOrderIDSTP);
StaticVarSet(“BuyCountDown”, BuyLockoutPeriod);
StaticVarSet(“timer2”, timer2Period);
SetChartBkColor( colorPink ); }
}
if( LastValue(Sell) AND ( SellOrderID == “” AND SellCountDown == 0
) AND ibc.GetPositionSize( Name() )==0
LastTradeOver==1)
{
_TRACE(“Trace 3# IF Able
to
Sell:”+(LastValue(Sell) AND ( BuyOrderID == “” AND BuyCountDown ==
0 ) AND
ibc.GetPositionSize( Name() )==0 AND LastTradeOver==1
));
if(GetRTData(“Bid”)>0.5 AND
int(Now(4)/100)0==22 AND Now(4)0<=30) {
SellOrderID = ibc.PlaceOrder(Name(), “SELL”, 95100,
“MKT”, 0, 0, “Day”, False);
SellOrderIDSTP=ibc.PlaceOrder(Name(), “BUY”, 95100, “STP”, 0,
GetRTData(“bid”)+0.00150, “GTC”, False,1,””, SellOrderID);
SellOrderIDLMT=ibc.PlaceOrder(Name(), “BUY”, 95100, “LMT”,
GetRTData(“bid”)-0.00150,0, “GTC”, True,1,””, SellOrderID);
AlertIf(1,
TRADE”+”xx”+Tol,Now(4));
StaticVarSetText(“SellOrderID”,SellOrderID);
StaticVarSetText(“SellOrderIDLMT”,SellOrderIDLMT);
StaticVarSetText(“SellOrderIDSTP”,SellOrderIDSTP);
StaticVarSet(“SellCountDown”, SellLockoutPeriod);
StaticVarSet(“timer2”, timer2Period);
SetChartBkColor( colorBlue);}
}
else if( Reset )
{
StaticVarSetText(“BuyOrderID”,””);
if( BuyPending ) ibc.CancelOrder( BuyOrderID );
StaticVarSetText(“SellOrderID”,””);
if( SellPending ) ibc.CancelOrder( SellOrderID );
ibc.CloseAllOpenPositions();
}
LastTWSMsg = ibc.getLastError( 0 );
BuyStatus = WriteIf( BuyOrderID != “”, BuyOrderID+”, Status:
“+ibc.GetStatus( BuyORderID, True ),””);
SellStatus= WriteIf( SellOrderID != “”, SellOrderID+”, Status:
“+ibc.GetStatus( SellORderID, True ),””);
LastBuyTime= Nz(StaticVarGet(“LastBuyTime”));
LastSellTime= Nz(StaticVarGet(“LastSellTime”));
Title = “\n”+
“Last TWS Error Msg: “+LastTWSMsg+”\n”+
” BuyOrderID: “+BuyStatus+”\n”+
” BuyCountDown: “+NumToStr(BuyCountDown,1.0,False)+” Sec.\n”+
” SellOrderID: “+SellStatus+”\n”+
” SellCountDown: “+NumToStr(SellCountDown,1.0,False)+”
Sec.”+”\n”+
” TWS Position Size: “+NumToStr(ibc.GetPositionSize( Name()
),1.0,False);
}
else
{
SetChartBkColor( colorPink );
following will display in the interpretation window
“\n1. Autotrading is turned off\n” + “2. TWS to Internet is .”
);
ibc = GetTradingInterface(“IB”);
}
Plot(C,”Close”,colorBlack);
Plot(MA(C,80),”Close”,11,styleLine);
Plot(MA(C,640),”Close”,12,styleLine);
printf(“\nclose:”+C+”\nma(c,108):”+MA(C,108)+”\n”);
//_TRACE(“Trace 1# IF Able to Trade:”+(StaticVarGet( “sAutoTrading”
) AND (ConnectedStatus==2 OR ConnectedStatus == 3 ) AND
Nz(GetRTData(“Bid”),0)));
Plot(GetRTData(“bid”),”bid”,11,styleLine);
Plot(GetRTData(“ask”),”ask”,12,styleLine);
timer1Period = Param(“timer1Period”,30,1,300,1);
printf(“\ntimer2:”+timer2+”\n”);
if( NewSecond )
{
timer1 = Max( 0, Nz(StaticVarGet(“timer1”))-1);
StaticVarSet(“timer1”, timer1);
}
timer1 = Nz(StaticVarGet(“timer1”));
Lstmin=LastValue(Minute());
zz=abs(int(Now(4)/100)0-Lstmin);
printf(“min:”+int(Now(4)/100)0+”\nsec:”+LastValue(Now(4)0)+”\ntim:”+timer1+”\nlstmin:”+Lstmin);
if(timer1==0)
{
a=Now(4);
size= int(ibc.GetPositionSize( “eur.usd-idealpro-cash”));
text=”Hold:”+size+”//”+”Total:”+Tol;
AlertIf(int(Now(4)/100)0==0 AND
Now(4)0<=30,
“EMAIL”,text,a);
AlertIf(abs(size)!=95100 AND abs(size)!=0 AND
GetRTData(“Bid”)>0 , “EMAIL”,text,a);
AlertIf( (zz>1 AND zz<59) OR zero1==1
, “EXEC c:\\1.exe”,””,a);
//jl
fh = fopen( “c:\\SaveData\\”+Name()+”.txt”, “w”);
if( fh )
{
execlist = ibc.GetExecList(0,””); // all
execinfo = “”;
for( i = 0;( OId = StrExtract( execlist, i ) ) != “”; i++ )
{
Symbol: ” + ibc.GetExecInfo( OID, “Symbol” ) +
” Filled: ” + ibc.GetExecInfo( OID, “Filled” ) +
” Avg. price: ” + ibc.GetExecInfo( OID, “Avg. price” )
+
}
fputs( execinfo, fh );
fclose( fh );
}
//jl
StaticVarSet(“timer1”, timer1Period);
}
}
else
{Title=”Please Check the Internet Connection”;}
_SECTION_END();
############################################
<ControlPanelInclude-001.afl>
procedure kStaticVarSet( SName, SValue )
Svalue);
function kStaticVarGet( SName )
procedure kStaticVarSetText( SName, SValue )
Svalue);
function kStaticVarGetText( SName )
function Column_Begin( ColName )
CellWidth, PanelXoffset, PanelYoffset;
800 );
function Column_End( )
PanelXoffset, ColNumber, RowNumber;
NumToStr(GetChartID(),1.0,False);
VarGetText(“ColName”);
PanelXoffset + (ColNumber-1) * CellWidth;
ULCellX + CellWidth;
Row++ )
PanelYoffset;
ULCellY + CellHeight;
kStaticVarGetText(“TextCell”+ColName+Row);
Nz(kStaticVarGet(“TextColor”+ColName+Row));
Nz(kStaticVarGet(“BackColor”+ColName+Row));
BackColor);
LRCellX, LRCellY );
BackColor);
);
ULCellY, LRCellX, LRCellY, 32 | 1 | 4);
function TextCell( TextCell, backColor, TextColor)
Nz(kStaticVarGet(“RowNumber”+ColName))+1;
RowNumber);
TextCell);
TextColor);
backColor);
function NewColumn()
function CheckMouseClick( ColNumber, RowNumber )
CellWidth;
* CellWidth;
ULCellX + CellWidth;
PanelYoffset;
ULCellY + CellHeight;
Nz(StaticVarGet(“ClickCoordinates”));
LButtonDown )
GetCursorXPosition( 1 );
GetCursorYPosition( 1 );
> ULCellX AND MousePx < LRCellX AND
MousePy > ULCellY AND MousePy <
LRCellY )
= 1;
function TriggerCell( Label, backColor1, BackColor2,
TextColor)
Nz(kStaticVarGet(“RowNumber”+ColName))+1;
RowNumber);
);
BackColor = backColor1;
Label);
TextColor);
backColor);
}
###################################
1.au3(ab假死恢复)
1);
MouseClick(“left”, 714, 615, 1);
################################
11.au3(ab崩溃恢复)
WinWait ( “AmiBroker crash recovery system”)
If WinExists(“AmiBroker crash recovery system”) Then
( “broker.exe” )
run(“C:\Program Files\AmiBroker\Broker.exe”)
EndIf
第三周开始用95100的交易量交易,结果发现如果在交易点上出现了急速波动,还是无法避免最初提到的成交恶劣的情况(满足条件的30秒里多次交易),所以又加了一个计数器,使得现在一个小时里最多交易一次,第四周开始停止了这个实盘实验(一共亏了近2000刀,其中大约800是手续费,另外1200是各种程序出错导致),因为期货上的改动牵扯了大量精力,暂时放下外汇自动交易,目前遗留的问题是各种不常见的程序或者网络崩溃时的恢复(常见的已经解决)。可能等我在自己家里安好服务器之后在努力一段时间就能真正用了。这次努力使我对autoit和powershell等DD有了好的运用,对于适合日内高频使用的自动交易策略有了更多的认识。