AccountManagerViewModel.cs 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491
  1. using System.Windows.Documents;
  2. using GalaSoft.MvvmLight;
  3. using GalaSoft.MvvmLight.Ioc;
  4. using Muchinfo.MTPClient.Data;
  5. using Muchinfo.MTPClient.Data.Enums;
  6. using Muchinfo.MTPClient.Data.Model;
  7. using Muchinfo.MTPClient.Data.Model.Account;
  8. using Muchinfo.MTPClient.Infrastructure.Cache;
  9. using Muchinfo.MTPClient.Infrastructure.Helpers;
  10. using Muchinfo.MTPClient.Infrastructure.MessageBox;
  11. using Muchinfo.MTPClient.Infrastructure.Utilities;
  12. using Muchinfo.MTPClient.IService;
  13. using Muchinfo.MTPClient.Resources;
  14. using Muchinfo.WPF.Controls.Windows;
  15. using System;
  16. using System.Collections.Generic;
  17. using System.Linq;
  18. using System.Timers;
  19. using System.Windows;
  20. using Direction = Muchinfo.MTPClient.Data.Enums.Direction;
  21. namespace Muchinfo.MTPClient.Account.ViewModels
  22. {
  23. public class AccountManagerViewModel : ViewModelBase
  24. {
  25. #region 字段
  26. private const int c_Interval = 5000; //定时器取数据时间
  27. private IOrderService _orderService;
  28. private ILoginService _loginService;
  29. private bool _isBusyFlag = false; //是否在取会员账号信息
  30. private int _showDialogCount = 0; //连续超过多少次超时才弹出超时对话框计数器
  31. private const int c_showdialog = 10; //计数常量
  32. private IGoodsService _goodsService;
  33. private ISystemService _systemService;
  34. private static object _lockObj=new object();
  35. private int interval; //定时器触发间隔
  36. private Timer _memberTimer; //会员账号信息定时器
  37. #endregion
  38. private bool _isMemberTrade ;
  39. /// <summary>
  40. /// 是否是要监控会员 交易员
  41. /// </summary>
  42. public bool IsMemberTrade
  43. {
  44. get
  45. {
  46. return _isMemberTrade;
  47. }
  48. }
  49. #region 构造函数
  50. /// <summary>
  51. ///
  52. /// </summary>
  53. public AccountManagerViewModel()
  54. {
  55. _systemService = SimpleIoc.Default.GetInstance<ISystemService>();
  56. _goodsService = SimpleIoc.Default.GetInstance<IGoodsService>();
  57. _orderService = SimpleIoc.Default.GetInstance<IOrderService>();
  58. _loginService = SimpleIoc.Default.GetInstance<ILoginService>();
  59. interval = ApplicationParameter.MemberMonitorTick <= 0
  60. ? c_Interval
  61. : ApplicationParameter.MemberMonitorTick * 1000;
  62. ////注册消息
  63. InitRegisterMsg();
  64. InitUpdateTradeInfo();
  65. }
  66. /// <summary>
  67. /// 初始化注册消息
  68. /// </summary>
  69. private void InitRegisterMsg()
  70. {
  71. MessengerHelper.DefaultRegister<bool>(this, MessengerTokens.MemberRolesToken, (val) =>
  72. {
  73. _isMemberTrade = val;
  74. lock (_lockObj)
  75. {
  76. if (val)
  77. {
  78. SimpleIoc.Default.GetInstance<IOrderService>().QueryMarketTypeStatus(MarketTypeStatusSuccess, null);
  79. }
  80. }
  81. });
  82. ////交易端的信息是否要更新
  83. MessengerHelper.DefaultRegister<bool>(this, MessengerTokens.MemberTraderUpdate, (val) =>
  84. {
  85. if (IsMemberTrade&&_memberTimer!=null)
  86. {
  87. if (!val)
  88. {
  89. ////所有市场收市
  90. _memberTimer.Stop();
  91. }
  92. else
  93. {
  94. if (!_memberTimer.Enabled)
  95. {
  96. _memberTimer.Start();
  97. }
  98. }
  99. }
  100. });
  101. MessengerHelper.DefaultRegister<string>(this, MessengerTokens.UpdateAccountCommand, CalcuatePLWithoutQuote);
  102. MessengerHelper.DefaultRegister<TradeAccount>(this, MessengerTokens.HolderUpdate, (e) =>
  103. {
  104. InitUpdateTradeInfo();
  105. });
  106. // 委托单成交通知
  107. //MessengerHelper.DefaultUnregister<ulong>(this, MessengerTokens.ShowMOOrdersByCapitalAccount);
  108. //MessengerHelper.DefaultRegister<ulong>(this, MessengerTokens.ShowMOOrdersByCapitalAccount, (e) =>
  109. //{
  110. // InitUpdateTradeInfo();
  111. //});
  112. ////注册实时行情消息
  113. MessengerHelper.QuoteRegister<List<QuoteGoods>>(this, MessengerTokens.ReceiveRealTimeQuote, (quoteList) =>
  114. {
  115. if (UserManager.CurrentTradeAccount == null) return;
  116. if (quoteList == null || !quoteList.Any()) return;
  117. foreach (var item in quoteList)
  118. {
  119. if (item == null) continue;
  120. //更新盈亏
  121. // var goodsPips = UserManager.GetTraderGoodsPips(UserManager.CurrentTradeAccount.TradeCode, item.GoodsCode);
  122. UpdateFloatPL(item);
  123. }
  124. MessengerHelper.DefaultSend(UserManager.CurrentTradeAccount, MessengerTokens.UpdateAccountFloatPL);
  125. });
  126. //单据成交时需重新计算盈亏
  127. MessengerHelper.DefaultRegister<TradeAccount>(this, MessengerTokens.OrderNotify, (e) =>
  128. {
  129. InitUpdateTradeInfo();
  130. });
  131. }
  132. void MarketTypeStatusSuccess(List<MarketTypeProperty> marketList)
  133. {
  134. if (marketList != null && marketList.Any())
  135. {
  136. foreach (var marketTypeProperty in marketList)
  137. {
  138. if (CacheManager.MarketStatus.ContainsKey(marketTypeProperty.markettypeid))
  139. {
  140. CacheManager.MarketStatus[marketTypeProperty.markettypeid] = marketTypeProperty.Inreckon;
  141. }
  142. }
  143. if (_memberTimer == null)
  144. {
  145. _memberTimer = new Timer();
  146. _memberTimer.Interval = interval;
  147. _memberTimer.Elapsed += _memberTimer_Elapsed;
  148. }
  149. var allMarketType = CacheManager.MarketStatus.Values.Any((status) => status == (int)MarketStatus.MarketOpen);
  150. if (allMarketType)
  151. {
  152. if (!_memberTimer.Enabled)
  153. {
  154. _memberTimer.Start();
  155. }
  156. }
  157. }
  158. }
  159. void _memberTimer_Elapsed(object sender, ElapsedEventArgs e)
  160. {
  161. if (IsMemberTrade)
  162. {
  163. if (!_isBusyFlag)
  164. {
  165. _isBusyFlag = true;
  166. ////_orderService.GetMemberAmountPosition(UserManager.CurrentTradeAccount);
  167. //if (UserManager.CurrentTradeAccount != null && UserManager.CurrentTradeAccount.FundsAccounts.Any())
  168. //{
  169. // _orderService.QueryMemberMonitor(UserManager.CurrentTradeAccount.FundsAccounts[0].AccountId, QuerySuccess, QueryErrorFunc);
  170. //}
  171. //else
  172. //{
  173. // LogInfoHelper.WriteInfo("请求会员监控信息:会员资金账号不存在 ");
  174. //}
  175. }
  176. }
  177. else
  178. {
  179. _memberTimer.Stop();
  180. }
  181. }
  182. public void QuerySuccess(List<MemberAccountInfo> successAction)
  183. {
  184. _isBusyFlag = false;
  185. _memberTimer.Interval = interval;
  186. _showDialogCount = 0; //收到回应时重置
  187. if (successAction != null && successAction.Count > 0)
  188. {
  189. UserManager.CurrentTradeAccount.MemberPositions = successAction[0].MemberPositions;
  190. if ((AccountStatus)successAction[0].AccountStatus != AccountStatus.None) ////从风控显示数据
  191. {
  192. var funds = UserManager.CurrentTradeAccount.FundsAccounts[0];
  193. successAction[0].Balance = funds.Balance;
  194. UserManager.CurrentTradeAccount.MemberAccountInfo = successAction[0];
  195. MessengerHelper.DefaultSend(successAction, MessengerTokens.MemberAccountUpdate);
  196. }
  197. else
  198. {
  199. ////从数据库中显示资金信息
  200. if (UserManager.CurrentTradeAccount.FundsAccounts != null &&
  201. UserManager.CurrentTradeAccount.FundsAccounts.Any())
  202. {
  203. var funds = UserManager.CurrentTradeAccount.FundsAccounts[0];
  204. var memberInfo = new MemberAccountInfo();
  205. memberInfo.UsedMargin = funds.UsedMargin ;
  206. memberInfo.FloatPL = funds.FloatPL ;
  207. memberInfo.NetWorth = funds.CurrentNetWorth ;
  208. memberInfo.AvailMargin = funds.AvailMargin;
  209. memberInfo.MemberPositions = successAction[0].MemberPositions;
  210. memberInfo.Balance = funds.Balance ;
  211. memberInfo.Rate = funds.RiskRatio;
  212. memberInfo.AccountStatus = UserManager.CurrentTradeAccount.AccountStatus;//账户状态
  213. UserManager.CurrentTradeAccount.MemberAccountInfo = memberInfo;
  214. memberInfo.MemberPositions = successAction[0].MemberPositions;
  215. MessengerHelper.DefaultSend(new List<MemberAccountInfo>() { memberInfo }, MessengerTokens.MemberAccountUpdate);
  216. }
  217. }
  218. }
  219. }
  220. private void QueryErrorFunc(ErrorEntity error)
  221. {
  222. _isBusyFlag = false;
  223. _memberTimer.Interval = interval;
  224. LogInfoHelper.WriteInfo(string.Format("请求会员风控信息错误({0}){1}", error.ReturnCode, error.ReturnDesc));
  225. //Application.Current.Dispatcher.BeginInvoke(new Action(() =>
  226. //{
  227. // ErrorManager.ShowReturnError(error, Client_Resource.UI2014_Tips, true);
  228. //}));
  229. }
  230. /// <summary>
  231. /// 初始化交易数据
  232. /// </summary>
  233. private void InitUpdateTradeInfo()
  234. {
  235. var queryCommonParams = new List<QueryCommonParam>();
  236. var accountid = UserManager.CurrentTradeAccount.LoginID;
  237. //if (UserManager.CurrentTradeAccount.FundsAccounts!=null && UserManager.CurrentTradeAccount.FundsAccounts.Any())
  238. //{
  239. // accountid = UserManager.CurrentTradeAccount.FundsAccounts[0].AccountId;
  240. //}
  241. queryCommonParams.Add(new QueryCommonParam() { ParamKey = "accountId", ParamValue = accountid + string.Empty });
  242. //初始化持仓单
  243. _loginService.LoginQuerySearch(Convert.ToUInt64(UserManager.CurrentTradeAccount.LoginID), LoginQueryType.TAAccountList, QueryHoldOrderCallBack, null);
  244. //_orderService.QueryHoldingDetails(QueryStatement.SearchMarketHoldOrder, queryCommonParams, QueryHoldOrderCallBack, null);
  245. }
  246. /// <summary>
  247. /// 查询持仓成功回调
  248. /// </summary>
  249. /// <param name="holdOrders">持仓内容</param>
  250. private void QueryHoldOrderCallBack(AccountBaseInfoModel holdOrders)
  251. {
  252. ////获取当前的持仓
  253. CalcuatePLWithoutQuote("");
  254. //MessengerHelper.DefaultSend(UserManager.CurrentTradeAccount, MessengerTokens.HolderRefresh);
  255. MessengerHelper.DefaultSend(UserManager.CurrentTradeAccount, MessengerTokens.UpdateAccountFloatPL);
  256. }
  257. #endregion
  258. #region 方法
  259. /// <summary>
  260. /// 没有行情时计算浮盈
  261. /// </summary>
  262. private void CalcuatePLWithoutQuote(string msg)
  263. {
  264. var quoteGoodses = CacheManager.CacheGoodsBaseInfos.Where((item)=>item.GoodsId!=0); //_goodsService.GetGoodsInfoListByExchangeId(UserManager.CurrentTradeAccount.ExchangeId);
  265. if (quoteGoodses != null && quoteGoodses.Any())
  266. {
  267. var dicGoods = quoteGoodses.ToDictionary((good) => good.GoodsId);
  268. UpdateFloatPL(dicGoods);
  269. }
  270. }
  271. /// <summary>s
  272. /// 更新当前持仓商品的平仓价,浮动盈亏
  273. /// </summary>
  274. /// <param name="quoteGoods">行情商品</param>
  275. private void UpdateFloatPL(Dictionary<uint, QuoteGoods> quoteGoodsDic)
  276. {
  277. // holdingReports = new ObservableCollection<OpenOrder>();
  278. if (UserManager.CurrentTradeAccount == null)
  279. {
  280. return;
  281. }
  282. var holdingReports = UserManager.CacheOpenOrders(UserManager.CurrentTradeAccount);
  283. if (holdingReports == null) return;
  284. foreach (var openOrder in holdingReports)
  285. {
  286. if (openOrder.MarketType == eTradeMode.TRADEMODE_SALE) ////发售的市值
  287. {
  288. openOrder.CurrentAmount = openOrder.HoldAmount;
  289. }
  290. if (!quoteGoodsDic.ContainsKey(openOrder.GoodsId) )
  291. {
  292. continue;
  293. }
  294. var orderGoods = quoteGoodsDic[openOrder.GoodsId];
  295. SetHorderClosePrice(openOrder,orderGoods);
  296. ////竞价盈亏
  297. //openOrder.ClosePrice = openOrder.QuoteGoods.GoodsParameters.TradeMode == TradeModeType.BidGoods
  298. // ? orderGoods.CurrentPrice
  299. // : openOrder.ClosePrice;
  300. openOrder.PLFloat = FloatPLExpressions.OrderDetailFloatPL(openOrder, orderGoods);
  301. openOrder.CurrentAmount = FloatPLExpressions.CalcHoldAmount(openOrder, orderGoods);
  302. //(openOrder.ClosePrice - openOrder.HoldingPrice) * openOrder.Lot * orderFlag
  303. //* openOrder.QuoteGoods.GoodsParameters.AgreeUnit;
  304. if (ApplicationParameter.IsShowSumPL == 1)
  305. {
  306. openOrder.SumFloatPL = FloatPLExpressions.CalcOrderDetailSumPL(openOrder);
  307. }
  308. }
  309. if (UserManager.CurrentTradeAccount != null && UserManager.CurrentTradeAccount.FundsAccounts != null &&
  310. UserManager.CurrentTradeAccount.FundsAccounts.Any())
  311. {
  312. decimal payPL, marginPL;
  313. FloatPLExpressions.CalcFullPayPLWithSumPL(holdingReports, out payPL, out marginPL);
  314. UserManager.CurrentTradeAccount.FundsAccounts[0].FloatPL = Math.Round(marginPL, 2);
  315. UserManager.CurrentTradeAccount.FundsAccounts[0].PayNetWorth =
  316. holdingReports.Sum((item) => item.CurrentAmount);
  317. }
  318. }
  319. /// <summary>s
  320. /// 更新当前持仓商品的平仓价,浮动盈亏
  321. /// </summary>
  322. /// <param name="quoteGoods">行情商品</param>
  323. private void UpdateFloatPL(QuoteGoods quoteGoods)
  324. {
  325. LogInfoHelper.WriteInfo("更新当前持仓商品的平仓价,浮动盈亏" + quoteGoods.GoodsClassName + quoteGoods.GoodsCode + DateTime.Now.ToString());
  326. if (UserManager.CurrentTradeAccount == null)
  327. {
  328. return;
  329. }
  330. var holdingReports = UserManager.CacheOpenOrders(UserManager.CurrentTradeAccount); ;
  331. if (holdingReports != null)
  332. {
  333. var openOrders = holdingReports.Where((order) => order.GoodsId == quoteGoods.GoodsId);
  334. foreach (var openOrder in openOrders)
  335. {
  336. SetHorderClosePrice(openOrder, quoteGoods);
  337. ////竞价盈亏
  338. //openOrder.ClosePrice = openOrder.QuoteGoods.GoodsParameters.TradeMode == TradeModeType.BidGoods
  339. // ? quoteGoods.CurrentPrice
  340. // : openOrder.ClosePrice;
  341. // }
  342. //todo:可计算浮动盈亏
  343. openOrder.PLFloat = FloatPLExpressions.OrderDetailFloatPL(openOrder, quoteGoods);
  344. openOrder.CurrentAmount = FloatPLExpressions.CalcHoldAmount(openOrder, quoteGoods);
  345. if (ApplicationParameter.IsShowSumPL==1)
  346. {
  347. openOrder.SumFloatPL = FloatPLExpressions.CalcOrderDetailSumPL(openOrder);
  348. }
  349. //(openOrder.ClosePrice - openOrder.HoldingPrice) * openOrder.Lot * orderFlag
  350. //* openOrder.QuoteGoods.GoodsParameters.AgreeUnit;
  351. }
  352. if (UserManager.CurrentTradeAccount != null && UserManager.CurrentTradeAccount.FundsAccounts != null &&
  353. UserManager.CurrentTradeAccount.FundsAccounts.Any())
  354. {
  355. decimal payPL, marginPL;
  356. FloatPLExpressions.CalcFullPayPLWithSumPL(holdingReports, out payPL, out marginPL);
  357. UserManager.CurrentTradeAccount.FundsAccounts[0].FloatPL = Math.Round(marginPL, 2);
  358. UserManager.CurrentTradeAccount.FundsAccounts[0].FloatPL = Math.Round(marginPL, 2);
  359. UserManager.CurrentTradeAccount.FundsAccounts[0].PayNetWorth =
  360. holdingReports.Sum((item) => item.CurrentAmount);
  361. }
  362. }
  363. }
  364. /// <summary>
  365. /// 设置持仓的最新价()
  366. /// </summary>
  367. /// <param name="holdingOrder">持仓单</param>
  368. /// <param name="orderGoods">持仓商品</param>
  369. private void SetHorderClosePrice(HoldingOrder holdingOrder, QuoteGoods orderGoods)
  370. {
  371. if (orderGoods != null )
  372. {
  373. switch (orderGoods.TradeMode)
  374. {
  375. case eTradeMode.TRADEMODE_MARKETMAKE:
  376. if (holdingOrder.Direction == Direction.Ask)
  377. {
  378. holdingOrder.ClosePrice = orderGoods.BidPrice;
  379. holdingOrder.ContrayClosePrice = orderGoods.AskPrice;
  380. }
  381. else
  382. {
  383. holdingOrder.ClosePrice = orderGoods.AskPrice;
  384. holdingOrder.ContrayClosePrice = orderGoods.BidPrice;
  385. }
  386. break;
  387. case eTradeMode.TRADEMODE_BIDDING:
  388. ///竞价盈亏
  389. holdingOrder.ClosePrice = orderGoods.CurrentPrice == 0 ? orderGoods.LastClose : orderGoods.CurrentPrice;
  390. break;
  391. case eTradeMode.TRADEMODE_SALE:
  392. holdingOrder.ClosePrice = holdingOrder.HoldingPrice; ////发售用持仓价来算市值
  393. break;
  394. case eTradeMode.TRADEMODE_BIDDINGMARKETMAKE:
  395. ///竞价盈亏
  396. holdingOrder.ClosePrice = orderGoods.CurrentPrice == 0 ? orderGoods.LastClose : orderGoods.CurrentPrice;
  397. break;
  398. default:
  399. break;
  400. }
  401. }
  402. else
  403. {
  404. ///竞价盈亏
  405. holdingOrder.ClosePrice = orderGoods.CurrentPrice == 0 ? orderGoods.LastClose : orderGoods.CurrentPrice;
  406. }
  407. }
  408. #endregion
  409. /// <summary>
  410. /// Cleanups this instance.
  411. /// </summary>
  412. public override void Cleanup()
  413. {
  414. ////取消注册消息
  415. base.Cleanup();
  416. MessengerHelper.QuoteUnregister(this);
  417. }
  418. }
  419. }