/// <summary> /// To get the file name by the type of data. /// </summary> /// <param name="dataType">Data type.</param> /// <param name="arg">The parameter associated with the <paramref name="dataType" /> type. For example, <see cref="CandleMessage.Arg"/>.</param> /// <returns>The file name.</returns> public static string GetFileName(Type dataType, object arg) { if (dataType == null) { throw new ArgumentNullException("dataType"); } if (dataType.IsSubclassOf(typeof(CandleMessage))) { return("candles_{0}_{1}".Put(dataType.Name.Replace("Message", string.Empty), TraderHelper.CandleArgToFolderName(arg))); } else { if (arg != null && arg.Equals(ExecutionTypes.Trade)) { arg = ExecutionTypes.Order; } var fileName = _fileNames.TryGetValue(Tuple.Create(dataType, arg)); if (fileName == null) { throw new NotSupportedException(LocalizedStrings.Str2872Params.Put(dataType.FullName)); } return(fileName); } }
//private void CandleManagerStopped(CandleSeries series) //{ // if (series == this) // Stopped.SafeInvoke(); //} //private void CandleManagerProcessing(CandleSeries series, Candle candle) //{ // if (series == this) // ProcessCandle.SafeInvoke(candle); //} ///// <summary> ///// Release resources. ///// </summary> //protected override void DisposeManaged() //{ // base.DisposeManaged(); // if (CandleManager != null) // CandleManager.Stop(this); //} /// <summary> /// Returns a string that represents the current object. /// </summary> /// <returns>A string that represents the current object.</returns> public override string ToString() { return(CandleType.Name + "_" + Security + "_" + TraderHelper.CandleArgToFolderName(Arg)); }
/// <summary> /// To get the file name by the type of data. /// </summary> /// <param name="dataType">Data type.</param> /// <param name="arg">The parameter associated with the <paramref name="dataType" /> type. For example, <see cref="CandleMessage.Arg"/>.</param> /// <returns>The file name.</returns> public static string GetFileName(Type dataType, object arg) { if (dataType == null) { throw new ArgumentNullException(nameof(dataType)); } if (dataType.IsCandleMessage()) { return("candles_{0}_{1}".Put(dataType.Name.Replace("Message", string.Empty), TraderHelper.CandleArgToFolderName(arg))); } else { var fileName = _fileNames.TryGetValue(DataType.Create(dataType, arg)); if (fileName == null) { throw new NotSupportedException(LocalizedStrings.Str2872Params.Put(dataType.FullName)); } return(fileName); } }
/// <summary> /// Получить название файла по типу данных. /// </summary> /// <param name="dataType">Тип маркет-данных.</param> /// <param name="arg">Параметр, ассоциированный с типом <paramref name="dataType"/>. Например, <see cref="CandleMessage.Arg"/>.</param> /// <returns>Название файла.</returns> public static string CreateFileName(Type dataType, object arg) { if (dataType == null) { throw new ArgumentNullException("dataType"); } if (dataType == typeof(ExecutionMessage)) { switch ((ExecutionTypes)arg) { case ExecutionTypes.Tick: return("trades"); case ExecutionTypes.Order: case ExecutionTypes.Trade: return("execution"); case ExecutionTypes.OrderLog: return("orderLog"); default: throw new ArgumentOutOfRangeException(); } } else if (dataType == typeof(QuoteChangeMessage)) { return("quotes"); } else if (dataType == typeof(Level1ChangeMessage)) { return("security"); } else if (dataType == typeof(NewsMessage)) { return("news"); } else if (dataType.IsSubclassOf(typeof(CandleMessage))) { return("candles_{0}_{1}".Put(dataType.Name.Replace("Message", string.Empty), TraderHelper.CandleArgToFolderName(arg))); } else { throw new NotSupportedException(LocalizedStrings.Str2872Params.Put(dataType.FullName)); } }
/// <summary> /// To get the file name by the type of data. /// </summary> /// <param name="dataType">Data type.</param> /// <param name="arg">The parameter associated with the <paramref name="dataType" /> type. For example, <see cref="CandleMessage.Arg"/>.</param> /// <param name="format">Storage format. If set an extension will be added to the file name.</param> /// <returns>The file name.</returns> public static string GetFileName(Type dataType, object arg, StorageFormats?format = null) { if (dataType == null) { throw new ArgumentNullException(nameof(dataType)); } string fileName; if (dataType.IsCandleMessage()) { fileName = "candles_{0}_{1}".Put(dataType.Name.Remove(nameof(Message)), TraderHelper.CandleArgToFolderName(arg)); } else { fileName = _fileNames.TryGetValue(DataType.Create(dataType, arg)); if (fileName == null) { throw new NotSupportedException(LocalizedStrings.Str2872Params.Put(dataType.FullName)); } } if (format != null) { fileName += GetExtension(format.Value); } return(fileName); }
/// <summary> /// Send message. /// </summary> /// <param name="message">Message.</param> protected override void OnSendInMessage(Message message) { switch (message.Type) { case MessageTypes.Reset: { if (_client != null) { DisposeClient(); } try { Connection.Close(); Connection.ClearCache(); } catch (Exception ex) { SendOutError(ex); } Connection.StatusChange -= ConnectionOnStatusChange; SendOutMessage(new ResetMessage()); break; } case MessageTypes.Connect: { if (_client != null) { throw new InvalidOperationException(LocalizedStrings.Str3378); } var doc = XDocument.Load("http://www.ddfplus.com/getusersettings.php?username={0}&password={1}".Put(Login, Password.To <string>())); var loginElem = doc.Element("usersettings").Elements("login").First(); if (loginElem.GetAttributeValue <string>("status") != "ok") { throw new InvalidOperationException(LocalizedStrings.UnknownServerError); } if (loginElem.GetAttributeValue <string>("credentials") != "ok") { throw new InvalidOperationException(LocalizedStrings.Str3350); } foreach (var elem in doc.Element("usersettings").Element("servers").Elements()) { switch (elem.GetAttributeValue <string>("type")) { case "stream": _streamAddress = elem.GetAttributeValue <string>("primary"); break; case "historicalv2": _historicalAddress = elem.GetAttributeValue <string>("primary"); break; case "extras": _extrasAddress = elem.GetAttributeValue <string>("primary"); break; case "news": _newsAddress = elem.GetAttributeValue <string>("primary"); break; } } SendOutMessage(new ConnectMessage()); Connection.StatusChange += ConnectionOnStatusChange; Connection.Properties["streamingversion"] = "3"; _client = new Client(); _client.Error += ClientOnError; _client.NewBookQuote += ClientOnNewBookQuote; _client.NewOHLCQuote += ClientOnNewOhlcQuote; _client.NewQuote += ClientOnNewQuote; Connection.Username = Login; Connection.Password = Password.To <string>(); Connection.Mode = ConnectionMode.TCPClient; break; } case MessageTypes.Disconnect: { if (_client == null) { throw new InvalidOperationException(LocalizedStrings.Str1856); } DisposeClient(); Connection.Close(); break; } case MessageTypes.SecurityLookup: { var lookupMsg = (SecurityLookupMessage)message; XDocument doc = null; if (!lookupMsg.SecurityId.SecurityCode.IsEmpty()) { doc = XDocument.Load("{0}/instruments/?lookup={1}".Put(_extrasAddress, lookupMsg.SecurityId.SecurityCode)); } else if (!lookupMsg.SecurityId.BoardCode.IsEmpty()) { doc = XDocument.Load("{0}/instruments/?exchange={1}".Put(_extrasAddress, lookupMsg.SecurityId.BoardCode)); } if (doc != null) { foreach (var element in doc.Element("instruments").Elements()) { SendOutMessage(new SecurityMessage { SecurityId = new SecurityId { SecurityCode = element.GetAttributeValue <string>("guid"), BoardCode = element.GetAttributeValue <string>("exchange"), }, Name = element.GetAttributeValue <string>("symbol_description"), OriginalTransactionId = lookupMsg.TransactionId, SecurityType = TraderHelper.FromIso10962(element.GetAttributeValue <string>("symbol_cfi")), PriceStep = element.GetAttributeValue <decimal?>("tick_increment"), Multiplier = element.GetAttributeValue <decimal?>("point_value"), Currency = element.GetAttributeValue <CurrencyTypes?>("currency") }); } } SendOutMessage(new SecurityLookupResultMessage { OriginalTransactionId = lookupMsg.TransactionId, }); break; } case MessageTypes.MarketData: { var mdMsg = (MarketDataMessage)message; switch (mdMsg.DataType) { case MarketDataTypes.Level1: break; case MarketDataTypes.MarketDepth: break; case MarketDataTypes.Trades: { if (mdMsg.Count != null || mdMsg.From != null || mdMsg.To != null) { var url = new Url("{0}/queryticks.ashx".Put(_historicalAddress)); url.QueryString .Append("username", Login) .Append("password", Password.To <string>()) .Append("symbol", mdMsg.SecurityId.SecurityCode) .Append("order", "asc"); if (mdMsg.Count != null) { url.QueryString.Append("maxrecords", mdMsg.Count.Value); } if (mdMsg.From != null) { url.QueryString.Append("start", mdMsg.From.Value.FromDateTimeOffset(_defaultTimeFormatRequest)); } if (mdMsg.To != null) { url.QueryString.Append("end", mdMsg.To.Value.FromDateTimeOffset(_defaultTimeFormatRequest)); } using (var client = new WebClient()) { var lines = client.DownloadString(url) .Split("\n") .Where(l => l != "\r") .ToArray(); var i = 0; foreach (var line in lines) { var columns = line.Split(','); try { var msg = new ExecutionMessage { SecurityId = mdMsg.SecurityId, OriginalTransactionId = mdMsg.TransactionId, ExecutionType = ExecutionTypes.Tick, ServerTime = columns[0].ToDateTime("yyyy-MM-dd HH:mm:ss.fff"), TradePrice = columns[3].To <decimal>(), Volume = columns[4].To <decimal>(), }; msg.AddValue("IsFinished", ++i == lines.Length); SendOutMessage(msg); } catch (Exception ex) { throw new InvalidOperationException(LocalizedStrings.Str2141Params.Put(line), ex); } } } } break; } case MarketDataTypes.News: break; case MarketDataTypes.CandleTimeFrame: { var tf = (TimeSpan)mdMsg.Arg; string serviceName; string timeFormatRequest = _defaultTimeFormatRequest; string timeFormatResponse = "yyyy-MM-dd"; if (tf == TimeSpan.FromMinutes(1)) { serviceName = "queryminutes"; timeFormatResponse = "yyyy-MM-dd HH:mm"; } else if (tf == TimeSpan.FromDays(1)) { serviceName = "queryeod"; timeFormatRequest = "yyyyMMdd"; } else { throw new InvalidOperationException(LocalizedStrings.Str2102); } var url = new Url("{0}/{1}.ashx".Put(_historicalAddress, serviceName)); url.QueryString .Append("username", Login) .Append("password", Password.To <string>()) .Append("symbol", mdMsg.SecurityId.SecurityCode) .Append("order", "asc"); if (mdMsg.Count != null) { url.QueryString.Append("maxrecords", mdMsg.Count.Value); } if (mdMsg.From != null) { url.QueryString.Append("start", mdMsg.From.Value.FromDateTimeOffset(timeFormatRequest)); } if (mdMsg.To != null) { url.QueryString.Append("end", mdMsg.To.Value.FromDateTimeOffset(timeFormatRequest)); } using (var client = new WebClient()) { var lines = client.DownloadString(url) .Split("\n") .Where(l => l != "\r") .ToArray(); var i = 0; foreach (var line in lines) { var columns = line.Split(','); try { SendOutMessage(new TimeFrameCandleMessage { SecurityId = mdMsg.SecurityId, OriginalTransactionId = mdMsg.TransactionId, OpenTime = columns[tf == TimeSpan.FromMinutes(1) ? 0 : 1].ToDateTime(timeFormatResponse).ApplyTimeZone(TimeHelper.Est), OpenPrice = columns[2].To <decimal>(), HighPrice = columns[3].To <decimal>(), LowPrice = columns[4].To <decimal>(), ClosePrice = columns[5].To <decimal>(), TotalVolume = columns[6].To <decimal>(), OpenInterest = columns.Length > 7 ? columns[7].To <decimal>() : (decimal?)null, IsFinished = ++i == lines.Length }); } catch (Exception ex) { throw new InvalidOperationException(LocalizedStrings.Str2141Params.Put(line), ex); } } } break; } default: { SendOutMarketDataNotSupported(mdMsg.TransactionId); return; } } SendOutMessage(new MarketDataMessage { OriginalTransactionId = mdMsg.TransactionId }); break; } } }
/// <summary> /// Получить название файла по типу данных. /// </summary> /// <param name="dataType">Тип маркет-данных.</param> /// <param name="arg">Параметр, ассоциированный с типом <paramref name="dataType"/>. Например, <see cref="Candle.Arg"/>.</param> /// <returns>Название файла.</returns> public static string CreateFileName(Type dataType, object arg) { if (dataType == null) { throw new ArgumentNullException("dataType"); } if (dataType == typeof(ExecutionMessage)) { var execType = (ExecutionTypes)arg; switch (execType) { case ExecutionTypes.Tick: dataType = typeof(Trade); break; case ExecutionTypes.Order: case ExecutionTypes.Trade: dataType = typeof(Order); break; case ExecutionTypes.OrderLog: dataType = typeof(OrderLogItem); break; default: throw new ArgumentOutOfRangeException(); } } else if (dataType.IsSubclassOf(typeof(CandleMessage))) { dataType = dataType.ToCandleType(); } else if (dataType == typeof(QuoteChangeMessage)) { dataType = typeof(MarketDepth); } if (dataType == typeof(Trade)) { return("trades"); } else if (dataType == typeof(MarketDepth)) { return("quotes"); } else if (dataType == typeof(OrderLogItem)) { return("orderLog"); } else if (dataType == typeof(Level1ChangeMessage)) { return("security"); } else if (dataType == typeof(Order)) { return("execution"); } else if (dataType.IsSubclassOf(typeof(Candle))) { return("candles_{0}_{1}".Put(dataType.Name, TraderHelper.CandleArgToFolderName(arg))); } else { throw new NotSupportedException(LocalizedStrings.Str2872Params.Put(dataType.FullName)); } }
/// <summary> /// Рассчитать прибыльность сделки. Если сделка уже ранее была обработана, то возвращается предыдущая информация. /// </summary> /// <param name="trade">Сделка.</param> /// <returns>Информация о новой сделке.</returns> public PnLInfo Process(ExecutionMessage trade) { if (trade == null) { throw new ArgumentNullException("trade"); } var closedVolume = 0m; var pnl = 0m; var volume = trade.GetVolume(); var price = trade.GetTradePrice(); _unrealizedPnL = null; lock (_openedTrades.SyncRoot) { if (_openedTrades.Count > 0) { var currTrade = _openedTrades.Peek(); if (_openedPosSide != trade.Side) { while (volume > 0) { if (currTrade == null) { currTrade = _openedTrades.Peek(); } var diff = currTrade.Second.Min(volume); closedVolume += diff; pnl += TraderHelper.GetPnL(currTrade.First, diff, _openedPosSide, price); volume -= diff; currTrade.Second -= diff; if (currTrade.Second != 0) { continue; } currTrade = null; _openedTrades.Pop(); if (_openedTrades.Count == 0) { break; } } } } if (volume > 0) { _openedPosSide = trade.Side; _openedTrades.Push(RefTuple.Create(price, volume)); } RealizedPnL += _multiplier * pnl; } return(new PnLInfo(trade, closedVolume, pnl)); }