创建broker工作流.docx
《创建broker工作流.docx》由会员分享,可在线阅读,更多相关《创建broker工作流.docx(19页珍藏版)》请在冰豆网上搜索。
创建broker工作流
创建broker工作流
1.在VisualStudio的视图设计器中打开eBrokerFlow项目中的Workflow1.cs文件。
2.我们需要插入一个Code活动,它被用来为一个Delay活动(你稍后将会插入它)指定预期的延迟时间,并初始化一些内部数据结构。
因此,拖拽一个Code活动到工作流视图设计器的界面上,然后在ExecuteCode属性中键入Initialize并按下回车键,以便在工作流代码中创建该Initialize事件处理程序。
然后,回到工作流的视图设计器界面上继续添加活动。
备注:
延时时间值保存在Settings(配置文件)中。
3.接下来拖拽一个EventHandlingScope到工作流视图设计器界面上。
4.记住,你需要为EventHandlingScope提供一个事件处理程序以及一个子活动,以便在它监听事件时执行。
我们首先创建事件处理程序。
为了存取这些事件处理程序,需要把鼠标指针移到eventHandlingScop1下面的微小矩形图标上。
(这个矩形就是一个“智能标记。
”)
然后这个矩形变成了一个更大、更黑并带有向下箭头的矩形。
点击这个向下的箭头,这会激活一个带有图标的四个快捷菜单:
查看EventHandlingScope、查看取消处理程序、查看错误处理程序和查看事件处理程序。
点击最下面的一个菜单项、切换到事件处理程序视图。
你看到的这个用户界面和你在第七章(“基本活动操作”)中看到的和错误处理程序相联系的用户界面很相似。
拖拽一个EventDriven活动到工作流视图设计器界面上,把它放到这个矩形的中间(在这里你会看到“将EventDrivenActivity拖放至此”的文字说明)。
5.现在回到工具箱中,在eBrokerFlow组件区域中找到Stop活动。
拖拽一个该活动到工作流视图设计器界面上,把它放进你在前一个步骤所添加的EventDriven活动中。
假如你想对多个事件进行监听的话,在这时你还可把它们都添加进去。
在我们的例子中,这里只有Stop事件是我们需要的。
6.你刚才就添加好了EventHandlingScope活动将对停止执行进行监听的事件。
下面,你需要为EventHandlingScope添加子活动,当监听到Stop活动触发时EventHandlingScope将执行这个子活动。
因此,我们需要通过第4步中的第一个子步骤回到eventHandlingScopeActivity1的查看EventHandlingScope界面上,但你需要选择最上面的菜单项,而不是最下面的一个。
7.拖拽一个While活动到工作流视图设计器界面上,把它放到EventHandlingScope活动内。
8.指定它的Condition属性为代码条件而不是声明性规则条件,指定该事件处理程序的名称为TestContinue。
一旦VisualStudio添加了该TestContinue事件处理程序后,需要回到工作流视图设计器上,还有更多的活动要进行添加。
9.While活动只能接受唯一的一个子活动,因此拖拽一个Sequence活动到该While活动中。
10.在这里你需要一个Code活动来对股票价值进行蒙特卡罗模拟,因此拖拽一个Code活动到视图设计器界面上,把它放进你在前一步骤所添加的Sequence活动中。
在属性窗口中把它重命名为updateMarket。
11.指定updateMarket这个Code活动的ExecuteCode属性为UpdateMarketValues。
在VisualStudio添加了相应的事件处理程序后回到工作流视图设计器界面上来,以便继续布置你的工作流。
12.在模拟完成后(你将添加的代码实际上就是进行模拟),你需要把这些潜在的进行了修改的值传给宿主应用程序。
为此,把鼠标指针移到工具箱上,找到你在IWFBroker中创建的MarketUpdate活动,把它拖到视图设计器界面上并放到Sequence活动中的你在前一步骤中所添加的Code活动的下面。
13.MarketUpdate活动需要把一小段XML放送给宿主,要做到这一点,它必须绑定到容纳有此时将发送的XML的字段属性。
为此,在VisualStudio的属性面板中选择xmlMarketValues属性,然后点击浏览(...)按钮,打开一个“将‘xmlMarketValues’绑定到活动的属性”的对话框。
然后点击绑定到新成员选项卡,点击创建属性,在新成员名称中输入Updates。
最后点击确定。
VisualStudio就添加了Updates这个依赖属性。
14.为了让你能处理来自于宿主的事件,拖拽一个Listen活动到设计器界面上,把它放进Sequence活动中。
15.假如你回忆一下,你会记起IWFBroker接口声明了五个事件,它们中的一个是我们已经用过的Stop,还有四个事件要去处理。
Listen活动目前仅仅容纳了两个EventDriven活动,但添加更多的EventDriven活动也很容易。
你需要简单地拖拽多达三个的EventDriven活动进Listen活动中。
为什么要添加三个而不是正好的两个呢?
因为第五个EventDriven活动要包含一个行为像是定时器的Delay活动,当延时过期后,Listen活动会结束该工作流线程。
然后While活动对执行条件进行检测判断,而返回的这个条件总被设置为true,于是使While活动不停地循环。
在股票价值被更新并发送给宿主后,Listen活动又对新一轮来自宿主的事件进行监听。
16.在最右边的EventDriven活动中,拖拽并放入一个Delay活动,在属性面板中把它命名为updateDelay。
17.接下来从eBrokerFlow中拖拽一个SellStock活动到工作流视图设计器界面上,把它放到从右边数起的第二个EventDriven活动中。
18.在VisualStudio的属性面板中选择NumberOfShares属性,点击浏览(...)按钮,这会又一次打开一个“将‘NumberOfShares’绑定到活动的属性”的对话框。
点击绑定到新成员选项卡,然后再点击创建字段,并在新成员名称中输入_sharesToSell,最后点击确定。
VisualStudio就添加了这个_sharesToSell字段。
备注:
我在这里选择创建_sharesToSell依赖属性而不是字段是因为字段从来不会被Workflow1类的外部访问到。
它提供的基于XML格式的市场价值信息要传给宿主,因此应当把外部访问权限暴露出来。
19.Symbol属性也必须进行绑定。
下面的步骤和上一步骤是一样的,只是字段名称要命名为_tickerToSell。
20.为了卖出股票,要拖拽一个Code活动放到SellStock事件处理程序的下面。
在它的ExecuteCode属性中输入SellStock,在插入了对应的事件处理程序后请回到工作流视图设计器界面上来。
21.我们现在要对买股票的逻辑进行添加。
拖拽一个BuyStock事件处理活动(也来自于eBrokerFlow)到设计器界面上,把它放到正中间的EventDriven活动中。
22.使用第18步的步骤,把BuyStock活动的NumberOfShares属性绑定到一个新的字段,名称为_sharesToBuy。
同样,使用第19步的步骤,把它的Symbol属性也绑定到一个新的字段,名称为_tickerToBuy。
23.和你需要一个Code活动去卖股票一样,你也需要一个Code活动去买股票。
重复第12步添加一个新的Code活动,设置它的ExecuteCode属性为BuyStock。
24.重复第17步至第20步两次,把RemoveTicker和AddTicker事件也添加到Listen活动中。
RemoveTicker活动的TickerXML属性要绑定到一个新的名称为_tickerToRemove的字段,而为该RemoveTicker事件添加的Code活动的ExecuteCode属性指定为RemoveTicker。
同样地,AddTicker活动的TickerXML属性要绑定到_tickerToAdd,和它相联系的Code活动的ExecuteCode属性指定为AddTicker。
完成这些后,Listen活动的外观如下所示:
25.编译你的这个工作流,纠正任何出现的编译错误。
26.在VisualStudio中打开Workflow1.cs的源文件准备进行编辑。
27.VisualStudio为你添加了大量的代码,因此你首先定位到Workflow1的构造器并在该构造器下添加如下的代码。
你插入的这些代码可被认为是初始化代码。
当工作流启动时,你将把一个数据字典传给该工作流,这个数据字典包含有以股票代码(如“CONT”)作为关键字的要监视的若干股票信息的集合。
你也需要指定一个轮询间隔,它是再一次对股票市值进行检测前工作流所要等待的时间值。
privateDictionary_items=
newDictionary();
privatestring_tickersXML=null;
publicstringTickersXML
{
get{return_tickersXML;}
set{_tickersXML=value;}
}
privateTimeSpan_interval=TimeSpan.FromSeconds(7);
publicTimeSpanPollInterval
{
get{return_interval;}
set{_interval=value;}
}
28.下面定位到你在步骤2中为你的第一个Code活动添加的Initialize事件处理程序。
插入下面的代码:
Initialize
//Establishthemarketupdatetimeout
updateDelay.TimeoutDuration=PollInterval;
//Stufftheknowntickervaluesintothedictionary
//forlaterrecallwhenupdatingmarketconditions.
eBrokerService.Tickerstickers=null;
using(StringReaderrdr=newStringReader(TickersXML))
{
XmlSerializerserializer=
newXmlSerializer(typeof(eBrokerService.Tickers));
tickers=(eBrokerService.Tickers)serializer.Deserialize(rdr);
}
foreach(eBrokerService.Tickertickerintickers.Items)
{
//Addthetickertothedictionary
_items.Add(ticker.Symbol,ticker);
}
提示:
为了方便,我在这个初始化方法中对该Delay活动的TimeoutDuration进行了指定。
但是不要忘了,你也能使用Delay活动的InitializeTimeoutDuration方法来做同样的工作。
29.找到TestContinue事件处理程序,While活动使用它来对是否继续进行循环进行判断。
插入下面的代码让While活动不停循环(不用担心...实际上它最终会停止循环的!
):
//Continueforever
e.Result=true;
30.下面要插入的代码块很长,它使用了蒙特卡罗模拟来对股票市场价进行更新。
找到和名称为updateMarket的Code活动(参见第10步)相对应的UpdateMarketValues事件处理程序,插入下面的代码:
UpdateMarketValues
//Iterateovereachiteminthedictionaryanddecide
//whatit'scurrentvalueshouldbe.Normallywe'dcall
//someexternalservicewitheachofourwatchvalues,
//butfordemopurposeswe'lljustuserandomvalues.
Randomrand=newRandom(DateTime.Now.Millisecond);
eBrokerService.UpdateCollectionupdates=neweBrokerService.UpdateCollection();
foreach(stringkeyin_items.Keys)
{
//Locatetheitem
eBrokerService.Tickeritem=_items[key];
//Ifwe'restartingout,wehavenocurrentvalue,
//soplacethevalueathalfthedistancebetweenthe
//buyandselltriggers.
if(item.LastPrice<=0.0m)
{
//Assignaprice
decimaldelta=(item.SellTrigger-item.BuyTrigger)/2.0m;
//Thelastpricemustbeapositivevalue,soadd
//thedeltatothesmallervalue.
if(delta>=0.0m)
{
//Adddeltatobuytriggervalue
item.LastPrice=item.BuyTrigger+delta;
}//if
else
{
//Reverseitandaddtotheselltrigger
//value
item.LastPrice=item.SellTrigger+delta;
}//else
}//if
//Setupthesimulation
decimalnewPrice=item.LastPrice;
decimalonePercent=item.LastPrice*0.1m;
Int32multiplier=0;//nochange
//We'llnowrollsomedice.Firstroll:
doesthe
//marketvaluechange?
0-79,no.80-99,yes.
if(rand.Next(0,99)>=80)
{
//Yes,updatetheprice.Nextroll:
willthe
//valueincreaseordecrease?
0-49,increase.
//50-99,decrease
multiplier=1;
if(rand.Next(0,99)>=50)
{
//Decreasetheprice.
multiplier=-1;
}//if
//Nextroll,byhowmuch?
We'llcalculateit
//asapercentageofthecurrentsharevalue.
//0-74,.1%change.75-89,.2%change.90-97,
//.3%change.And98-99,.4%change.
Int32roll=rand.Next(0,99);
if(roll<75)
{
//1%change
newPrice=item.LastPrice+(onePercent*multiplier*0.1m);
}//if
elseif(roll<90)
{
//2%change
newPrice=item.LastPrice+(onePercent*multiplier*0.2m);
}//elseif
elseif(roll<98)
{
//3%change
newPrice=item.LastPrice+(onePercent*multiplier*0.3m);
}//elseif
else
{
//4%change
newPrice=item.LastPrice+(onePercent*multiplier*0.4m);
}//elseif
}//if
else
{
//Nochangeinprice
newPrice=item.LastPrice;
}//else
//Nowcreatetheupdateforthisticker
eBrokerService.Updateupdate=neweBrokerService.Update();
update.Symbol=item.Symbol;
update.LastPrice=item.LastPrice;
update.NewPrice=newPrice;
update.Trend=multiplier>0?
"Up":
(multiplier==0?
"Firm":
"Down");
update.Action=newPrice>item.SellTrigger?
"Sell":
(newPrice"Buy":
"Hold");
update.TotalValue=newPrice*item.NumberOfShares;
updates.Add(update);
//Updatethedatastore
item.LastPrice=newPrice;
}//foreach
//Serializethedata
StringBuildersb=newStringBuilder();
using(StringWriterwtr=newStringWriter(sb))
{
XmlSerializerserializer=newXmlSerializer(typeof(eBrokerService.UpdateCollection));
serializer.Serialize(wtr,updates);
}//using
//Shipthedataback
Updates=sb.ToString();
基本上,每一次更新循环,对于每一只股票将有20%的几率被修改。
假如该股票的价格将被修改,它有一半的几率会上升,有一半的几率会下降。
将改变的值是:
有75%的几率是当前每股价格的1%,有15%的几率是当前每股价格的2%,有7%的几率是当前每股价格的3%,有3%的几率是当前每股价格的4%。
对于每一次循环,所有被监视的股票都会被更新,即使它的价格没有变化。
将被发送回宿主进行显示的数据是一个XML字符串,它包含有各只的股票代码、当前价格、根据所买的该只股票数计算出来的总市值、趋势(上升还是下降)以及是否有要进行买或卖的建议。
买卖建议会显示出一个醒目的标志(红或绿),你已经在图10-5中见过。
31.现在向外部事件处理程序中添加代码。
首先定位到SellStock事件处理程序,添加下面的代码:
SellStock
//Reducethenumberofsharesforthegiventicker.
try
{
//Findthisticker.
eBrokerService.Tickeritem=_items[_tickerToSell];
if(item!
=null)
{
//Reducethenumberofshares.
item.NumberOfShares=item.NumberOfShares-_sharesToSell>=0?
item.NumberOfShares-_sharesToSell:
0;
}
}
catch
{
//Donothingwejustwon'thavesoldany.
}
32.找到BuyStock事件处理程序,添加下面的代码:
BuyStock
//Increasethenumberofsharesforthegiventicker.
try
{
//Findthisticker.
eBrokerService.Tickeritem=_items[_tickerToBuy];
if(item!
=null)
{
//Increasethenumberofshares.
item.NumberOfShares+=_sharesToBuy;
}
}
catch
{
//Donothingwejustwon'thavepurchasedany.
}
33.接下来是RemoveTicker,找到它并插入下面的代码:
RemoveTicker
//Removethegiventickerfromthewatch.
try
{
//Deserialize
eBrokerService.Tickerticker=null;
using(StringReade