Advertisement
Guest User

Untitled

a guest
Apr 18th, 2019
270
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 63.61 KB | None | 0 0
  1. using System;
  2. using System.Collections.Concurrent;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. using System.Text.RegularExpressions;
  6. using System.Threading;
  7. using System.Web;
  8. using Brokerware.MDS.Common;
  9. using com.neovest.api;
  10. using com.neovest.api.common;
  11. using com.neovest.api.symbol;
  12. using com.neovest.connection;
  13. using com.neovest.fa.data;
  14. using com.neovest.fa.@event;
  15. using com.neovest.util;
  16. using System.Globalization;
  17. using NLog;
  18. using System.Diagnostics;
  19.  
  20. namespace Brokerware.MDS.Services
  21. {
  22.     public class NeovestQuotesProvider : IQuotesUpdater, IQuotesProvider, IQuotesObservable
  23.     {
  24.         Logger _logger = LogManager.GetCurrentClassLogger();
  25.         private SDKSymbolService _service;
  26.         private SymbolListener _listener = new SymbolListener();
  27.         internal static ConcurrentDictionary<string, Quotable> _quotables = new ConcurrentDictionary<string, Quotable>();
  28.         private static NeovestQuotesProvider _instance;
  29.         protected SDKServiceFactory _factory = SDKServiceFactory.getInstance();
  30.         public delegate void SampleRecordReceivedEventHandler(object sender, SampleRecordReceivedEventArgs e);
  31.         private MyConnectionListener connectionListener;
  32.         private static string _optionTickerRegex = @"^[A-Z]{1,6}[1-2][0-9][0-1][0-9][0-3][0-9][CP][0-9]{8}$";
  33.         private static string _optionSymbolNeovestRegex = @"^[A-Z]{1,6}[A-X][0-9]{4}[0-9]{1,4}(\.[0-9]{1,4})?$";
  34.         private DataRequestManager _reqManager = DataRequestManager.Instance;
  35.         private Dictionary<string, StockCodes> _codes = new Dictionary<string, StockCodes>();
  36.  
  37.         public string Name { get { return "neovest"; } }
  38.        
  39.         public ConnectionStatus Status { get; private set; }
  40.  
  41.         /*<Nuevo>*/
  42.         private YahooQuotesProvider _yahooQuotesProvider = YahooQuotesProvider.Instance;
  43.         private ConcurrentDictionary<string, Option> _options = new ConcurrentDictionary<string, Option>();
  44.         private ConcurrentDictionary<string, string[]> _optionChains = new ConcurrentDictionary<string, string[]>();//clave: subyacente y fecha de vencimiento (date), valores: tickers de las opciones para ahorrarme el ir a yahoo a buscarlos.
  45.         private ConcurrentDictionary<string, Stock> _stocks = new ConcurrentDictionary<string, Stock>();
  46.         private ConcurrentDictionary<string, SymbolSubcriptionKey> _subscriptionKeys = new ConcurrentDictionary<string, SymbolSubcriptionKey>(); //para guardar las claves y desuscribir despues
  47.         public event QuoteUpdateHandler OnQuoteUpdate;
  48.         private ConcurrentDictionary<string, UpdateMessage> _updates = new ConcurrentDictionary<string, UpdateMessage>();
  49.         private ConcurrentDictionary<string, UpdateMessage> _accumulatedUpdates = new ConcurrentDictionary<string, UpdateMessage>();
  50.         /*</Nuevo>*/
  51.  
  52.         private NeovestQuotesProvider()
  53.         {
  54.             _service = _factory.getSymbolService();
  55.             _reqManager.NewRequest += _reqManager_NewRequest;
  56.             connectionListener = new MyConnectionListener();
  57.             connectionListener.MDDisconnected += new EventHandler(connectionListener_MDDisconnected);
  58.             connectionListener.OEDisconnected += new EventHandler(connectionListener_OEDisconnected);
  59.             connectionListener.ConnectionRecordReceived += new SampleRecordReceivedEventHandler(connectionListener_ConnectionRecordReceived);
  60.             _factory.addConnectionListener(connectionListener);
  61.             _listener.QuoteUpdateReceived += quoteUpdateHandler;
  62.             marketDataLogin();
  63.         }
  64.  
  65.         private void _reqManager_NewRequest(SubscriptionRequest request)
  66.         {
  67.             switch (request.Type)
  68.             {
  69.                 case SubscriptionRequest.ReqType.StockQuote:
  70.                     request.RequestStatus = SubscriptionRequest.Status.Working;
  71.                     requestStockQuotes(request);
  72.                     break;
  73.                 case SubscriptionRequest.ReqType.StockQuotes:
  74.                     request.RequestStatus = SubscriptionRequest.Status.Working;
  75.                     requestStockQuotes(request);
  76.                     break;
  77.                 case SubscriptionRequest.ReqType.OptionQuote:
  78.                     break;
  79.                 case SubscriptionRequest.ReqType.OptionsList:
  80.                     break;
  81.                 case SubscriptionRequest.ReqType.OptionsQuoteList:
  82.                     request.RequestStatus = SubscriptionRequest.Status.Working;
  83.                     requestOptions(request);
  84.                     break;
  85.                 case SubscriptionRequest.ReqType.OptionsQuoteNTMList:
  86.                     break;
  87.                 case SubscriptionRequest.ReqType.HistoricalQuote:
  88.                     break;
  89.                 case SubscriptionRequest.ReqType.FundamentalData:
  90.                     request.RequestStatus = SubscriptionRequest.Status.Working;
  91.                     requestFundamentalData(request.Parameters["symbol"], request);
  92.                     break;
  93.                 case SubscriptionRequest.ReqType.SymbolGuide:
  94.                     break;
  95.                 case SubscriptionRequest.ReqType.OptionContract:
  96.                     break;
  97.                 case SubscriptionRequest.ReqType.StockCodes:
  98.                     request.RequestStatus = SubscriptionRequest.Status.Working;
  99.                     requestCodes(request.Parameters["symbol"], request);
  100.                     break;
  101.                 case SubscriptionRequest.ReqType.StockQuoteSubscription:
  102.                     break;
  103.                 case SubscriptionRequest.ReqType.QuotesSubscription:
  104.                     request.RequestStatus = SubscriptionRequest.Status.Working;
  105.                     DoQuotesSubscription(request.Parameters.Values.ToArray(), request);
  106.                     break;
  107.                 case SubscriptionRequest.ReqType.QuotesUnsubscription:
  108.                     request.RequestStatus = SubscriptionRequest.Status.Working;
  109.                     DoQuotesUnsubscription(request.Parameters.Values.ToArray(), request);
  110.                     break;
  111.                 default:
  112.                     break;
  113.             }
  114.         }
  115.  
  116.         private void requestStockQuotes(SubscriptionRequest req)
  117.         {
  118.             //</Nuevo>
  119.             requestData(req.Parameters.Values.ToArray(), new GenericListener((si, sre) =>
  120.             {
  121.                 if (sre.getStatus() == SymbolRecordEvent.SUCCESS)
  122.                 {
  123.                     var symbolRecord = sre.getSymbolRecord();
  124.                     var ticker = standardSymbol(si.getSymbologySymbolString());
  125.                     List<Stock> Stocks = new List<Stock>();
  126.  
  127.                     Stock stock = new Stock(ticker);
  128.                     if (!_stocks.TryGetValue(ticker, out stock))
  129.                     {
  130.                         _stocks.TryAdd(ticker, new Stock(ticker));
  131.                         stock = _stocks[ticker];
  132.                     }
  133.                     //obtengo los datos
  134.                     stock.Ask = symbolRecord.getAsk();
  135.                     stock.Bid = symbolRecord.getBid();
  136.                     stock.Change = symbolRecord.getNet();
  137.                     stock.Last = symbolRecord.getLast();
  138.                     stock.High = symbolRecord.getHigh();
  139.                     stock.Low = symbolRecord.getLow();
  140.                     stock.Open = symbolRecord.getOpen();
  141.                     stock.Ticker = ticker;
  142.                     stock.Volume = symbolRecord.getVolume();
  143.  
  144.                     if (!req.State.ContainsKey(ticker))
  145.                         req.State.Add(ticker, "OK");
  146.                     if ((req.RequestStatus != SubscriptionRequest.Status.Served) && (req.State.Count == req.Parameters.Count))
  147.                     {
  148.                         foreach (string tickr in req.Parameters.Values)
  149.                         {
  150.                             Stock stk;
  151.                             string tickrStandard = standardSymbol(tickr);
  152.                             _stocks.TryGetValue(tickrStandard, out stk);
  153.                             Stocks.Add(stk);
  154.                         }
  155.                         lock (req)
  156.                         {
  157.                             req.Result = Stocks;
  158.                             _reqManager.SetServed(req);
  159.                         }
  160.                     }
  161.                 }
  162.             }), false);
  163.             //</Nuevo>
  164.         }
  165.  
  166.         //<Nuevo>
  167.         private void requestFundamentalData(string symbol, SubscriptionRequest req)
  168.         {
  169.  
  170.             var symbolInfo = new SymbologyInfo(nativeSymbol(symbol));
  171.  
  172.             var extraFields = new java.util.ArrayList();
  173.  
  174.             //PE
  175.             SymbolFieldDefRecord.Key PEKey = new SymbolFieldDefRecord.Key(SymbolConstants.PE, SymbolFieldTypeEnum.EXTENDED);
  176.  
  177.             var PEField = _service.getSymbolField(PEKey);
  178.             if (PEField != null)
  179.             {
  180.                 extraFields.add(PEField);
  181.             }
  182.  
  183.             //Dividend
  184.             SymbolFieldDefRecord.Key dividendKey = new SymbolFieldDefRecord.Key(SymbolConstants.Dividend, SymbolFieldTypeEnum.EXTENDED);
  185.  
  186.             var dividendField = _service.getSymbolField(dividendKey);
  187.             if (dividendField != null)
  188.             {
  189.                 extraFields.add(dividendField);
  190.             }
  191.  
  192.             //WkHigh52
  193.             SymbolFieldDefRecord.Key WkHigh52Key = new SymbolFieldDefRecord.Key(SymbolConstants.WkHigh52, SymbolFieldTypeEnum.EXTENDED);
  194.  
  195.             var WkHigh52Field = _service.getSymbolField(WkHigh52Key);
  196.             if (WkHigh52Field != null)
  197.             {
  198.                 extraFields.add(WkHigh52Field);
  199.             }
  200.  
  201.             //WkLow52
  202.             SymbolFieldDefRecord.Key WkLow52Key = new SymbolFieldDefRecord.Key(SymbolConstants.WkLow52, SymbolFieldTypeEnum.EXTENDED);
  203.  
  204.             var WkLow52Field = _service.getSymbolField(WkLow52Key);
  205.             if (WkLow52Field != null)
  206.             {
  207.                 extraFields.add(WkLow52Field);
  208.             }
  209.  
  210.             //Capital
  211.             SymbolFieldDefRecord.Key CapitalKey = new SymbolFieldDefRecord.Key(SymbolConstants.Capital, SymbolFieldTypeEnum.EXTENDED);
  212.  
  213.             var CapitalField = _service.getSymbolField(CapitalKey);
  214.             if (CapitalField != null)
  215.             {
  216.                 extraFields.add(CapitalField);
  217.             }
  218.  
  219.             //VolAvg60
  220.             SymbolFieldDefRecord.Key VolAvg60Key = new SymbolFieldDefRecord.Key(SymbolConstants.VolAvg60, SymbolFieldTypeEnum.EXTENDED);
  221.  
  222.             var VolAvg60Field = _service.getSymbolField(VolAvg60Key);
  223.             if (VolAvg60Field != null)
  224.             {
  225.                 extraFields.add(VolAvg60Field);
  226.             }
  227.  
  228.             //divExDate
  229.             SymbolFieldDefRecord.Key divExDateKey = new SymbolFieldDefRecord.Key(SymbolConstants.DivExDate, SymbolFieldTypeEnum.EXTENDED);
  230.  
  231.             var divExDateField = _service.getSymbolField(divExDateKey);
  232.             if (divExDateField != null)
  233.             {
  234.                 extraFields.add(divExDateField);
  235.             }
  236.  
  237.             var builder = new SymbolSubscriptionCriteria.Builder(symbolInfo);
  238.             builder.fields(extraFields);
  239.  
  240.  
  241.             _service.subscribeSymbol(/*symbolInfo */builder.build(), new GenericListener((si, sre) =>
  242.             {
  243.                 if (sre.getStatus() == SymbolRecordEvent.SUCCESS)
  244.                 {
  245.  
  246.                     var symbolRecord = sre.getSymbolRecord();
  247.  
  248.                     var PE = symbolRecord.getDoubleValue(PEField.getSymbolAttributeID(), 0.0); //PE
  249.                     var Dividend = symbolRecord.getDoubleValue(dividendField.getSymbolAttributeID(), 0.0);//Dividend
  250.                     var DivExDate = symbolRecord.getStringValue(divExDateField.getSymbolAttributeID(), "?"); //DivExDate
  251.                                                                                                              //var NET = symbolRecord.getStringValue(NETField.getSymbolAttributeID(), "?");
  252.                     var WkHigh52 = symbolRecord.getDoubleValue(WkHigh52Field.getSymbolAttributeID(), 0.0);//WkHigh52
  253.                     var WkLow52 = symbolRecord.getDoubleValue(WkLow52Field.getSymbolAttributeID(), 0.0);//WkLow52
  254.                     var Capital = symbolRecord.getDoubleValue(CapitalField.getSymbolAttributeID(), 0.0);//Capital
  255.                     var VolAvg60 = symbolRecord.getDoubleValue(VolAvg60Field.getSymbolAttributeID(), 0.0);//VolAvg60
  256.  
  257.                     FundamentalData ret = new FundamentalData();
  258.  
  259.                     //Capitalizacion - Market Cap
  260.                     ret.mktCap = Capital;
  261.                     //DividendoAnualPorcentaje - % Dividends
  262.                     ret.dividendYield = Dividend;
  263.                     //FechaExDividend - -ExDividend Date
  264.                     ret.exDivDate = DivExDate;
  265.                     //MaxUnAno - -Maximum of the year
  266.                     ret.high52 = WkHigh52;
  267.                     //MinUnAno - -Minimum pf the year
  268.                     ret.low52 = WkLow52;
  269.                     //Vol50dias - Average Volume
  270.                     ret.vol50DayAvg = VolAvg60;
  271.                     //RatioPE - Ratio P/E
  272.                     ret.peRatio = PE;
  273.  
  274.                     if (req.RequestStatus != SubscriptionRequest.Status.Served)
  275.                     {
  276.                         lock (req)
  277.                         {
  278.                             req.Result = ret;
  279.                             _reqManager.SetServed(req);
  280.                         }
  281.                     }
  282.                 }
  283.             }));
  284.         }
  285.         //</Nuevo>
  286.  
  287.         private void requestCodes(string symbol, SubscriptionRequest req)
  288.         {
  289.             var symbolInfo = new SymbologyInfo(nativeSymbol(symbol));
  290.             var extraFields = new java.util.ArrayList();
  291.             extraFields.add(_service.getSymbolField(new SymbolFieldDefRecord.Key(SymbolConstants.P_ISIN, SymbolFieldTypeEnum.EXTENDED)));
  292.  
  293.             var builder = new SymbolSubscriptionCriteria.Builder(symbolInfo);
  294.             builder.fields(extraFields);
  295.             var codes = new StockCodes() { Ticker = symbol };
  296.             if (!_codes.ContainsKey(symbol))
  297.                 _codes.Add(symbol, codes);
  298.  
  299.             _service.subscribeSymbol(symbolInfo, new GenericListener((si, sre) =>
  300.             {
  301.                 if (sre.getStatus() == SymbolRecordEvent.SUCCESS)
  302.                 {
  303.                     var symbolRecord = sre.getSymbolRecord();
  304.                     var isinField = _service.getSymbolField(new SymbolFieldDefRecord.Key(SymbolConstants.P_ISIN, SymbolFieldTypeEnum.EXTENDED));
  305.                     codes.ISIN = symbolRecord.getStringValue(isinField.getSymbolAttributeID(), "");
  306.                     var isin = symbolRecord.getSymbolDisplayString(SymbologyInfo.ISIN_SYMBOLOGY);
  307.                     if (isin != null && isin != "")
  308.                     {
  309.                         codes.ISIN = isin;
  310.                         req.Result = codes;
  311.                         _reqManager.SetServed(req);
  312.                     }
  313.                 }
  314.             }));
  315.         }
  316.  
  317.         private void quoteUpdateHandler(object sender, QuoteUpdateEventArgs args)
  318.         {
  319.             if (_quotables.ContainsKey(args.Ticker))
  320.             {
  321.                 _quotables[args.Ticker].UpdateData(args.Data);
  322.             }
  323.         }
  324.  
  325. #region Connection Handlers
  326.         private void connectionListener_ConnectionRecordReceived(object sender, SampleRecordReceivedEventArgs e)
  327.         {
  328.             System.Diagnostics.Debug.WriteLine(e.SampleRecord);
  329.         }
  330.  
  331.         private void connectionListener_OEDisconnected(object sender, EventArgs e)
  332.         {
  333.         }
  334.  
  335.         private void connectionListener_MDDisconnected(object sender, EventArgs e)
  336.         {
  337.             bool connected = false;
  338.             while (connected == false)
  339.             {
  340.                 try
  341.                 {
  342.                     marketDataLogin();
  343.                     connected = true;
  344.                 }
  345.                 catch (Exception ex)
  346.                 {
  347.                     System.Diagnostics.Debug.WriteLine(ex.Message);
  348.                     System.Diagnostics.Debug.WriteLine(ex.StackTrace);
  349.                 }
  350.             }
  351.         }
  352. #endregion
  353.  
  354.         private void marketDataLogin()
  355.         {
  356.             ServerIPAndPort[] mdservers = new ServerIPAndPort[] {
  357.                 new ServerIPAndPort("directfeed.neovest.com", 5600),
  358.                 new ServerIPAndPort("directfeed2.neovest.com", 5600)
  359.             };
  360.  
  361.             MDAuthInfo mdAuthInfo = new MDAuthInfo("p-bnypaul1", "Jaci1605*", "Idealink", mdservers);
  362.  
  363.             try
  364.             {
  365.                 _factory.loginMarketData(mdAuthInfo);
  366.             }
  367.             catch (Exception e)
  368.             {
  369.                 System.Diagnostics.Debug.WriteLine(e.Message);
  370.                 System.Diagnostics.Debug.WriteLine(e.StackTrace);
  371.                 //cleanup();
  372.             }
  373.         }
  374.  
  375.         public static NeovestQuotesProvider Instance
  376.         {
  377.             get
  378.             {
  379.                 if (_instance == null)
  380.                     _instance = new NeovestQuotesProvider();
  381.                 return _instance;
  382.             }
  383.         }
  384.  
  385.         private void requestData(string[] symbols, SymbolRecordListener listener, bool subscribe = true)
  386.         {
  387.             var aditionalFields = new java.util.ArrayList();
  388.             aditionalFields.add(SymbolConstants.VWAP);
  389.             foreach (var symbol in symbols)
  390.             {
  391.                 SymbologyInfo symbolInfo = new SymbologyInfo();
  392.                 if (isOption(symbol))
  393.                 {
  394.                     symbolInfo.setIdType(SymbologyInfo.NEOVEST_SYMBOLOGY);
  395.                     //symbolInfo.setSymbolType(SymbologyInfo.OPTIONS_SYMBOL_TYPE);
  396.                     symbolInfo.setExchangeCode(ExchangeCode.getExchangeCode("OPR"));
  397.                     symbolInfo.setSymbologySymbolString(symbol);
  398.                 }
  399.                 else
  400.                 {
  401.                     symbolInfo.setIdType(SymbologyInfo.NEOVEST_SYMBOLOGY);
  402.                     //symbolInfo.setIdType(SymbologyInfo.BLOOMBERG_SYMBOLOGY);
  403.                     //symbolInfo.setExchangeCode(ExchangeCode.getExchangeCode("NAS"));
  404.                     symbolInfo.setSymbologySymbolString(symbol);
  405.                 }
  406.  
  407.                 ///New way of subscribing
  408.                 int updateInterval = 0; // how often to be updated on a given symbol.  0 for immediate
  409.                 SymbolSubscriptionCriteria.Builder subscribeCriteriaBuilder = new SymbolSubscriptionCriteria.Builder(symbolInfo);
  410.                 //subscribeCriteriaBuilder.fields(aditionalFields);
  411.                 if (subscribe)
  412.                 {
  413.                     subscribeCriteriaBuilder.updateInterval(updateInterval);
  414.                     _service.subscribeSymbol(subscribeCriteriaBuilder.build(), listener);
  415.                 }
  416.                 //<Nuevo>
  417.                 else
  418.                 {
  419.                     SymbolSubcriptionKey subscriptionKey;
  420.                     if (!_subscriptionKeys.TryGetValue(symbol, out subscriptionKey))
  421.                     {
  422.                         subscriptionKey = _service.allocateSubscriptionKey();
  423.                         _subscriptionKeys.TryAdd(symbol, subscriptionKey);
  424.                     }
  425.                     _logger.Info(string.Format("Subscribiendose para el ticker: {0}, SubscriptionKey: {1}", symbol, subscriptionKey));
  426.                     _service.subscribeSymbol(symbolInfo, listener, subscriptionKey);
  427.                 }
  428.                 //</Nuevo>
  429.             }
  430.         }
  431.  
  432.         private static bool isOption(string symbol)
  433.         {
  434.             return Regex.IsMatch(symbol, _optionSymbolNeovestRegex)
  435.                 || Regex.IsMatch(symbol, _optionTickerRegex);
  436.         }
  437.  
  438.         public void StopUpdate(Quotable quote)
  439.         {
  440.  
  441.         }
  442.  
  443.         public bool Update(Quotable quote, bool subscribe)
  444.         {
  445.             this.UpdateMultiple(new Quotable[] { quote });
  446.             return true;
  447.         }
  448.  
  449.         public bool UpdateMultiple(IEnumerable<Quotable> quotes)
  450.         {
  451.             var toSubscribe = new List<string>();
  452.             foreach (var q in quotes)
  453.             {
  454.                 if (!_quotables.ContainsKey(q.Ticker))
  455.                 {
  456.                     _quotables.AddOrUpdate(q.Ticker, q, (k, p) => q);
  457.                     toSubscribe.Add(nativeSymbol(q.Ticker));
  458.                 }
  459.             }
  460.             requestData(toSubscribe.ToArray(), _listener);
  461.             return true;
  462.         }
  463.  
  464.         /// <summary>
  465.         /// Returns Newovest symbol given a OCC option symbol or nasdaq stock symbol
  466.         /// </summary>
  467.         /// <param name="symbol">OCC symbol in case of options or Nasdaq symbol (ticker) en case of stock.</param>
  468.         /// <returns></returns>
  469.         public static string nativeSymbol(string symbol)
  470.         {
  471.             string ret = symbol;
  472.             if (Regex.IsMatch(symbol.ToUpper(), _optionTickerRegex))
  473.             {
  474.                 ret = "";
  475.                 //convert T181221C00028500 -> TL211828.5000 and also convert  T181221C00150000 -> TL2118150.000
  476.                 string underlyer = symbol.Substring(0, symbol.Length - 15);
  477.                 int underlyerLenght = underlyer.Length;
  478.  
  479.                 ret = ((char)('A' + int.Parse(symbol.Substring(symbol.Length - 13, 2)) - 1 + (symbol.Substring(symbol.Length - 9, 1) == "P" ? 12 : 0))).ToString()
  480.                     + symbol.Substring(symbol.Length - 11, 2) //en el ejemplo, 21, o sea, el dia.
  481.                     + symbol.Substring(symbol.Length - 15, 2) //en el ejemplo, 18, o sea, el año.
  482.                     + int.Parse(symbol.Substring(symbol.Length - 8, 5)).ToString()//la parte entera del strike, en este caso 00028, pero parseado queda 28.
  483.                     + "." + symbol.Substring(symbol.Length - 3);
  484.  
  485.                 ret = ret.PadRight(12, '0');
  486.  
  487.                 ret = underlyer + ret;
  488.             }
  489.             switch (symbol)
  490.             {
  491.                 case "DOWJONES":
  492.                     ret = "DJI2MN";
  493.                     break;
  494.                 case "COMP":
  495.                     ret = "COMPX";
  496.                     break;
  497.                 case "SPX":
  498.                     ret = "SPX.X";
  499.                     break;
  500.                 //<nuevo>
  501.                 case "PBR-A":
  502.                     ret = "PBR.A";
  503.                     break;
  504.                 case "BRKB":
  505.                     ret = "BRK.B";
  506.                     break;
  507.                     //</nuevo>
  508.             }
  509.             return ret;
  510.         }
  511.         /// <summary>
  512.         /// Returns a OCC option symbol or Nasdaq stock symbol given a Neovest symbol
  513.         /// </summary>
  514.         /// <param name="symbol">Newovest symbol</param>
  515.         /// <returns></returns>
  516.         public static string standardSymbol(string symbol)
  517.         {
  518.             var calls = "ABCDEFGHIJKL";
  519.             var puts = "MNOPQRSTUVWX";
  520.             var ret = symbol;
  521.             if (isOption(symbol))
  522.             {
  523.                 //convert TL211828.5000 -> T181221C00028500
  524.                 //also convert TL2118150.000 -> T181221C00150000
  525.                 var m = Regex.Match(symbol, "[A-X][0-3]");
  526.                 var underlying = symbol.Substring(0, m.Index);
  527.                 var monthCallCode = symbol.Substring(underlying.Length, 1);// "L"
  528.  
  529.                 string[] partesDelStrike = symbol.Substring(underlying.Length + 5).Split('.'); //se saltea "L2118" y toma 28.5000, que separa en 28 y 5000
  530.                 partesDelStrike[0] = partesDelStrike[0].PadLeft(5, '0');
  531.                 partesDelStrike[1] = partesDelStrike[1].Substring(0, 3);
  532.                 string strike = partesDelStrike[0] + partesDelStrike[1];
  533.  
  534.                 ret = underlying
  535.                    + symbol.Substring(underlying.Length + 3, 2)
  536.                    + (calls.IndexOf(monthCallCode) != -1
  537.                         ? (calls.IndexOf(monthCallCode) + 1).ToString().PadLeft(2, '0')
  538.                         : (puts.IndexOf(monthCallCode) + 1).ToString().PadLeft(2, '0'))
  539.                    + symbol.Substring(underlying.Length + 1, 2)
  540.                    + (calls.IndexOf(monthCallCode) != -1 ? "C" : "P")
  541.                    + strike;
  542.             }
  543.             switch (symbol)
  544.             {
  545.                 case "DJI2MN":
  546.                     ret = "DOWJONES";
  547.                     break;
  548.                 case "COMPX":
  549.                     ret = "COMP";
  550.                     break;
  551.                 case "SPX.X":
  552.                     ret = "SPX";
  553.                     break;
  554.                 //<nuevo>
  555.                 case "PBR.A":
  556.                     ret = "PBR-A";
  557.                     break;
  558.                 case "BRK.B":
  559.                     ret = "BRKB";
  560.                     break;
  561.                     //</nuevo>
  562.             }
  563.             return ret;
  564.         }
  565.  
  566.  
  567.         internal delegate void handleSymbolEvent(SymbologyInfo si, SymbolRecordEvent sre);
  568.  
  569.         internal class GenericListener : SymbolRecordListener
  570.         {
  571.             private SDKSymbolService _service;
  572.             private handleSymbolEvent _handler;
  573.  
  574.             public GenericListener(handleSymbolEvent handler)
  575.             {
  576.                 this._handler = handler;
  577.             }
  578.             public long getSupportedEventTypeMask()
  579.             {
  580.                 return SymbolRecordEvent.ALL_CHANGES;
  581.             }
  582.  
  583.             public void handleEvent(SymbologyInfo si, SymbolRecordEvent sre)
  584.             {
  585.                 _handler?.Invoke(si, sre);
  586.             }
  587.         }
  588.  
  589.  
  590.         internal class SymbolListener : SymbolRecordListener
  591.         {
  592.             internal delegate void QuoteUpdateReceivedEventHandler(object sender, QuoteUpdateEventArgs args);
  593.             internal event QuoteUpdateReceivedEventHandler QuoteUpdateReceived;
  594.  
  595.             public SymbolListener()
  596.             {
  597.  
  598.             }
  599.  
  600.             public long getSupportedEventTypeMask()
  601.             {
  602.                 return SymbolRecordEvent.ALL_CHANGES;
  603.             }
  604.  
  605.             public void handleEvent(SymbologyInfo si, SymbolRecordEvent sre)
  606.             {
  607.                 var handleAfterHoursQuotes = true;
  608.  
  609.                 if (sre.getStatus() == SymbolRecordEvent.SUCCESS)
  610.                 {
  611.                     var symbolrecord = sre.getSymbolRecord();
  612.                     var updMsg = new UpdateMessage();
  613.                     var symbol = NeovestQuotesProvider.standardSymbol(si.getDisplayString());
  614.                     var exchange = symbolrecord.getExchangeCode().getExchangeName();
  615.                     if (true || symbolrecord.isMarketOpen())
  616.                     {
  617.                         switch (sre.getEventType())
  618.                         {
  619.                             case SymbolRecordEvent.TRADE_CHANGES:
  620.                             case SymbolRecordEvent.BID_CHANGES:
  621.                             case SymbolRecordEvent.ASK_CHANGES:
  622.                             case SymbolRecordEvent.PCLOSE_CHANGES:
  623.                             case SymbolRecordEvent.NEW_HIGH_CHANGES:
  624.                             case SymbolRecordEvent.NEW_LOW_CHANGES:
  625.  
  626.                                 updMsg.Ticker = symbol;
  627.                                 Quotable quote = null;
  628.                                 _quotables.TryGetValue(symbol, out quote);
  629.  
  630.                                 if (quote == null)
  631.                                 {
  632.                                     if (symbolrecord.isOption())
  633.                                         quote = new Option(symbol, SymbolType.Ticker);
  634.                                     else
  635.                                         quote = new Stock(symbol);
  636.                                     _quotables.AddOrUpdate(symbol, quote, (k, p) => quote);
  637.                                 }
  638.  
  639.                                 if (quote != null)
  640.                                 {
  641.                                     updMsg.Ask = symbolrecord.getAsk() != quote.Ask ? symbolrecord.getAsk() : updMsg.Ask;
  642.                                     updMsg.Bid = symbolrecord.getBid() != quote.Bid ? symbolrecord.getBid() : updMsg.Bid;
  643.                                     updMsg.Change = symbolrecord.getNet() != quote.Change ? symbolrecord.getNet() : updMsg.Change;
  644.                                     updMsg.High = symbolrecord.getHigh() != quote.High ? symbolrecord.getHigh() : updMsg.High;
  645.                                     updMsg.Last = symbolrecord.getLast() != quote.Last ? symbolrecord.getLast() : updMsg.Last;
  646.                                     updMsg.Close = symbolrecord.getPClose() != quote.LastClose ? symbolrecord.getPClose() : updMsg.Close;
  647.                                     updMsg.Low = symbolrecord.getLow() != quote.Low ? symbolrecord.getLow() : updMsg.Low;
  648.                                     updMsg.Open = symbolrecord.getOpen() != quote.Open ? symbolrecord.getOpen() : updMsg.Open;
  649.                                     updMsg.Volume = symbolrecord.getVolume() != quote.Volume ? symbolrecord.getVolume() : updMsg.Volume;
  650.                                     //quote.VWAP = symbolrecord.getAsk() != quote.Ask ? symbolrecord.getAsk() : quote.Ask;
  651.  
  652.                                     if (symbolrecord.getLast() != 0)
  653.                                         updMsg.ChangePercent = symbolrecord.getNet() != quote.Change ? symbolrecord.getNet() / symbolrecord.getLast() * 100 : updMsg.ChangePercent;
  654.  
  655.                                     if (sre.getEventType() == SymbolRecordEvent.TRADE_CHANGES
  656.                                        || sre.getEventType() == SymbolRecordEvent.BID_CHANGES
  657.                                        || sre.getEventType() == SymbolRecordEvent.ASK_CHANGES)
  658.                                     {
  659.                                         SymbolTradeBidAskChangedEvent sTBAChangedEvent = sre as SymbolTradeBidAskChangedEvent;
  660.                                         var info = sTBAChangedEvent.getTradeBidAskInfo();
  661.  
  662.                                         updMsg.Time = Utils.GetDateTimeFromUnixTimestamp(info.getTimeStamp(), false);
  663.                                     }
  664.                                 }
  665.                                 if (updMsg.HasAnyValue)
  666.                                     QuoteUpdateReceived?.Invoke(this, new QuoteUpdateEventArgs(0, symbol, updMsg));
  667.                                 break;
  668.  
  669.                             case SymbolRecordEvent.GENERAL_CHANGES:
  670.                                 break;
  671.  
  672.                             case SymbolRecordEvent.SYMBOL_COMPLETE:
  673.  
  674.                                 break;
  675.                             default:
  676.                                 break;
  677.                         }
  678.                     }
  679.                 }
  680.                 else
  681.                 {
  682.                     //TODO: Handle error
  683.                 }
  684.             }
  685.         }
  686.  
  687.         private class MyConnectionListener : SDKServiceConnectionListener
  688.         {
  689.             internal event EventHandler MDDisconnected;
  690.             internal event EventHandler OEDisconnected;
  691.             internal event SampleRecordReceivedEventHandler ConnectionRecordReceived;
  692.  
  693.             public void connectionUpdate(SDKServiceConnectionEvent sdksce)
  694.             {
  695.                 int eventType = sdksce.getEventType();
  696.                 if (eventType == SDKServiceConnectionEvent.UNEXPECTED_DISCONNECT)
  697.                 {
  698.                     SDKServerInfo info = sdksce.getServerInfo();
  699.                     SDKServerInfo.ConnectionType connectionType = info.getType();
  700.                     if (connectionType == SDKServerInfo.ConnectionType.MARKET_DATA)
  701.                     {
  702.                         OnMDDisconnected();
  703.                     }
  704.                     else if (connectionType == SDKServerInfo.ConnectionType.ORDER_ENTRY)
  705.                     {
  706.                         OnOEDisconnected();
  707.                     }
  708.                 }
  709.                 else if (eventType == SDKServiceConnectionEvent.EXPECTED_DISCONNECT)
  710.                 {
  711.                     OnConnectionRecordReceived(new SampleRecordReceivedEventArgs("Connection updated - eventType: " + eventType));
  712.                 }
  713.             }
  714.  
  715.             private void OnMDDisconnected()
  716.             {
  717.                 if (MDDisconnected != null)
  718.                     MDDisconnected(this, EventArgs.Empty);
  719.             }
  720.  
  721.             private void OnOEDisconnected()
  722.             {
  723.                 if (OEDisconnected != null)
  724.                     OEDisconnected(this, EventArgs.Empty);
  725.             }
  726.  
  727.             private void OnConnectionRecordReceived(SampleRecordReceivedEventArgs e)
  728.             {
  729.                 if (ConnectionRecordReceived != null)
  730.                     ConnectionRecordReceived(this, e);
  731.             }
  732.         }
  733.         public class SampleRecordReceivedEventArgs : EventArgs
  734.         {
  735.             private string sampleRecord;
  736.  
  737.             public SampleRecordReceivedEventArgs(string sRecord)
  738.             {
  739.                 sampleRecord = sRecord;
  740.             }
  741.  
  742.             public string SampleRecord
  743.             {
  744.                 get { return sampleRecord; }
  745.             }
  746.         }
  747.  
  748.  
  749.  
  750.         /*<Nuevo>*/
  751.         public StockCodes GetCodes(string ticker)
  752.         {
  753.             StockCodes codes = new StockCodes() { Ticker = ticker };
  754.             var parameters = new Dictionary<string, string>() { { "symbol", ticker } };
  755.             var req = new SubscriptionRequest(parameters, SubscriptionRequest.ReqType.StockCodes);
  756.             req = _reqManager.Submit(req);
  757.             _reqManager.WaitServed(req, 10000 /*10 segundos*/);
  758.             _codes.TryGetValue(ticker, out codes);
  759.  
  760.             return codes;
  761.         }
  762.  
  763.         /*</Nuevo>*/
  764.  
  765.         public FundamentalData GetFundamentalData(string symbol)
  766.         {
  767.  
  768.             //envio mi request y espero que quede servida
  769.             Dictionary<string, string> parameters = new Dictionary<string, string>();
  770.             parameters.Add("symbol", nativeSymbol(symbol));
  771.             SubscriptionRequest req = new SubscriptionRequest(parameters, SubscriptionRequest.ReqType.FundamentalData);
  772.             req = _reqManager.Submit(req);
  773.             _reqManager.WaitServed(req, 10000);
  774.  
  775.             //obtengo el resultado de la request
  776.             FundamentalData resultadoDeLaRequest = (FundamentalData)req.Result;
  777.             resultadoDeLaRequest.symbol = symbol;
  778.             return resultadoDeLaRequest;
  779.         }
  780.  
  781.         public HistoricQuoteItem[] GetHistoricalQuotes(string ticker, string from, string frequency)
  782.         {
  783.             throw new NotImplementedException();
  784.         }
  785.  
  786.         /// <summary>
  787.         /// Method that returns an "OptionChainResponse" with all the options requested.
  788.         /// </summary>
  789.         /// <param name="req">Request que contiene en "Parameters" la lista de los tickers</param>
  790.         private void requestOptions(SubscriptionRequest req)
  791.         {
  792.             Stopwatch stopwatch = new Stopwatch();
  793.             stopwatch.Start();
  794.             _logger.Info("Requesting options for from Neovest...");
  795.             List<OptionPair> optPairsRet = new List<OptionPair>();
  796.             requestData(req.Parameters.Values.ToArray(), new GenericListener((si, sre) =>
  797.             {
  798.                 if (sre.getStatus() == SymbolRecordEvent.SUCCESS)
  799.                 {
  800.                     var symbolRecord = sre.getSymbolRecord();
  801.                     var ticker = si.getSymbologySymbolString();//standardSymbol(si.getSymbologySymbolString());
  802.                     Option option;
  803.                     string tickrStandard = standardSymbol(ticker);
  804.  
  805.                     if (!_options.TryGetValue(tickrStandard, out option))
  806.                     {
  807.                         _options.TryAdd(tickrStandard, new Option(tickrStandard, SymbolType.Ticker));
  808.                         option = _options[tickrStandard];
  809.                     }
  810.                     //obtengo los datos
  811.                     option.Ask = symbolRecord.getAsk();
  812.                     option.Bid = symbolRecord.getBid();
  813.                     option.Change = symbolRecord.getNet();
  814.                     option.Last = symbolRecord.getLast();
  815.                     option.High = symbolRecord.getHigh();
  816.                     option.Low = symbolRecord.getLow();
  817.                     option.Open = symbolRecord.getOpen();
  818.                     option.Ticker = ticker;
  819.                     option.Volume = symbolRecord.getVolume();
  820.  
  821.  
  822.                     lock (req)
  823.                     {
  824.                         if (!req.State.ContainsKey(ticker))
  825.                         {
  826.                             req.State.Add(ticker, "OK");
  827.                             _logger.Info(string.Format("Datos obtenidos para el ticker: {0}", ticker));
  828.                         }
  829.                         if ((req.RequestStatus != SubscriptionRequest.Status.Served) && (req.State.Count == req.Parameters.Count))
  830.                         {
  831.  
  832.                             OptionChainResponse optionChain = new OptionChainResponse();
  833.                             List<Option> Calls = new List<Option>();
  834.                             List<Option> Puts = new List<Option>();
  835.  
  836.                             foreach (string tickr in req.Parameters.Values)
  837.                             {
  838.                                 Option opt = new Option();
  839.                                 tickrStandard = standardSymbol(tickr);
  840.  
  841.                                 if (_options.TryGetValue(tickrStandard, out opt)) //para evitar la nullpointerException.
  842.                                 {
  843.                                     if (opt.Type == OptionType.Call)
  844.                                     {
  845.                                         Calls.Add(opt);
  846.                                     }
  847.                                     else
  848.                                     {
  849.                                         Puts.Add(opt);
  850.                                     }
  851.                                 }
  852.                                 else
  853.                                 {
  854.                                     _logger.Info(string.Format("Error al obtener datos para el ticker: {0}", tickr));
  855.                                 }
  856.                             }
  857.  
  858.                             optionChain.Calls = Calls.ToArray();
  859.                             optionChain.Puts = Puts.ToArray();
  860.  
  861.                             req.Result = optionChain;
  862.                             _reqManager.SetServed(req);
  863.                         }
  864.                     }
  865.                 }
  866.             }), false);
  867.         }
  868.  
  869.         /// <summary>
  870.         /// convierto un ticker call en uno put y viceversa. Simplemente cambia la C por la P
  871.         /// </summary>
  872.         /// <param name="ticker">Ticker en formato Yahoo</param>
  873.         /// <param name="tipoFinal">Tipo del que va a ser el ticker devuelto</param>
  874.         /// <returns></returns>
  875.         public static string transformarTipoDeTicker(string ticker, char tipoFinal)
  876.         {
  877.             return ticker.Substring(0, ticker.Length - 9) + tipoFinal.ToString() + ticker.Substring(ticker.Length - 8);
  878.         }
  879.  
  880.         /// <summary>
  881.         /// convierto la optionChainResponse "chain" en una lista de pares de opciones :)
  882.         /// </summary>
  883.         /// <param name="chain">:)</param>
  884.         /// <returns></returns>
  885.         private OptionPair[] createOptPairsFromChain(OptionChainResponse chain)
  886.         {
  887.             List<OptionPair> ret = new List<OptionPair>();
  888.             if (chain.Calls.Length != chain.Puts.Length)
  889.             {
  890.                 _logger.Info("Error: la cadena generada no tiene la misma cantidad de puts que de calls. No se pueden crear Option pairs.");
  891.                 throw new Exception();
  892.             }
  893.             if (chain != null)
  894.             {
  895.                 //primero pongo todas las calls en los pares de opciones que voy a devolver.
  896.                 chain.Calls.OrderBy(call => call.Ticker);
  897.                 chain.Puts.OrderBy(put => put.Ticker);
  898.  
  899.                 foreach (Option call in chain.Calls) //creo un par por cada call y lo agrego a ret. Luego a ese par le voy a completar el "put"
  900.                 {
  901.                     OptionPair optPair = new OptionPair();
  902.  
  903.                     optPair.CallAsk = call.Ask;
  904.                     optPair.CallBid = call.Bid;
  905.                     optPair.CallChange = call.Change;
  906.                     optPair.CallLast = call.Last;
  907.                     optPair.CallTicker = call.Ticker;
  908.                     optPair.CallVolume = call.Volume;
  909.                     optPair.Strike = call.Strike;// puedo tomar el strike del call o del put, es el mismo.  
  910.  
  911.                     ret.Add(optPair);
  912.                 }
  913.  
  914.                 int i = 0;
  915.                 foreach (Option put in chain.Puts) //agrego los puts a los pares de opciones. Como estan ordenados por ticker simplemente los agrego uno a uno a los pares.
  916.                 {
  917.                     ret[i].PutAsk = put.Ask;
  918.                     ret[i].PutBid = put.Bid;
  919.                     ret[i].PutChange = put.Change;
  920.                     ret[i].PutLast = put.Last;
  921.                     ret[i].PutTicker = put.Ticker;
  922.                     ret[i].PutVolume = put.Volume;
  923.                     i++;
  924.                 }
  925.             }
  926.  
  927.             return ret.ToArray();
  928.         }
  929.  
  930.         public OptionPair[] GetOptionChain(string symbol, string date, int start, int count) //
  931.         {
  932.             //declaro variables iniciales
  933.             Dictionary<string, string> parameters = new Dictionary<string, string>();
  934.             int i = 1;
  935.             string ticker;
  936.             var culture = CultureInfo.InvariantCulture;
  937.             DateTime fecha;
  938.  
  939.             if (!DateTime.TryParseExact(date, "MMMyy;yyyy-MM-dd;yyyyMMdd".Split(';'), culture, DateTimeStyles.None, out fecha))
  940.                 throw new ApplicationException("date format not supported.");
  941.  
  942.  
  943.             string key = symbol + "-" + fecha;
  944.             string[] tickers; //para guardar la lista de tickers que devuelve mi "cache"
  945.  
  946.             if (_optionChains.TryGetValue(key, out tickers))// si es esta en la cache, entonces no es necesario pedir los datos a yahoo nuevamente.
  947.             {
  948.                 _logger.Info(string.Format("Obtenidas de Yahoo: {0}", tickers.Length));
  949.                 foreach (string s in tickers)
  950.                 {
  951.                     ticker = s;
  952.                     parameters.Add("Ticker" + i.ToString(), ticker);
  953.                     i++;
  954.                 }
  955.             }
  956.             else //si no estaba en mi "cache", entonces pido los datos a yahoo! y los guardo en un nuevo registro de mi diccionario cache.
  957.             {
  958.                 List<string> tckrs = new List<string>();//para mi cache
  959.  
  960.                 OptionPair[] optionChainYahoo = _yahooQuotesProvider.GetOptionChain(symbol, date, start, count);
  961.  
  962.                 //convierto los nombres a "native" para que neovest los entienda
  963.                 foreach (OptionPair opt in optionChainYahoo)
  964.                 {
  965.                     if ((opt.CallTicker != null) && (opt.PutTicker != null))
  966.                     {
  967.                         //Para verificar que es un call (dado que yahoo a veces se confunde y manda puts por calls y viceversa. Es decir, un optionPair con dos calls o dos puts. Pasa con AA-20191005)
  968.                         string callTicker = transformarTipoDeTicker(opt.CallTicker, 'C');
  969.                         ticker = nativeSymbol(callTicker);
  970.                         parameters.Add("Ticker" + i.ToString(), ticker);
  971.                         tckrs.Add(ticker);//para mi cache
  972.                         i++;
  973.  
  974.                         //Para verificar que es un put (dado que yahoo a veces se confunde y manda puts por calls y viceversa. Es decir, un optionPair con dos calls o dos puts. Pasa con AA-20191005)
  975.                         string putTicker = transformarTipoDeTicker(opt.PutTicker, 'P');
  976.                         ticker = nativeSymbol(putTicker);
  977.                         parameters.Add("Ticker" + i.ToString(), ticker);
  978.                         tckrs.Add(ticker);//para mi cache
  979.                         i++;
  980.                     }
  981.                     else if ((opt.CallTicker != null) && (opt.PutTicker == null))
  982.                     {
  983.                         ticker = nativeSymbol(opt.CallTicker);
  984.                         parameters.Add("Ticker" + i.ToString(), ticker);
  985.                         tckrs.Add(ticker);//para mi cache
  986.                         i++;
  987.  
  988.                         string putTicker = transformarTipoDeTicker(opt.CallTicker, 'P');
  989.                         ticker = nativeSymbol(putTicker);
  990.                         parameters.Add("Ticker" + i.ToString(), ticker);
  991.                         tckrs.Add(ticker);//para mi cache
  992.                         i++;
  993.                     }
  994.                     else if ((opt.CallTicker == null) && (opt.PutTicker != null))
  995.                     {
  996.                         string callTicker = transformarTipoDeTicker(opt.PutTicker, 'C');
  997.                         ticker = nativeSymbol(callTicker);
  998.                         parameters.Add("Ticker" + i.ToString(), ticker);
  999.                         tckrs.Add(ticker);//para mi cache
  1000.                         i++;
  1001.  
  1002.  
  1003.                         ticker = nativeSymbol(opt.PutTicker);
  1004.                         parameters.Add("Ticker" + i.ToString(), ticker);
  1005.                         tckrs.Add(ticker);//para mi cache
  1006.                         i++;
  1007.                     }
  1008.                 }
  1009.                 _logger.Info(string.Format("Obtenidas de Yahoo: {0}", tckrs.Count()));
  1010.                 _optionChains.TryAdd(key, tckrs.ToArray());//los guardo en un nuevo registro de mi diccionario cache.
  1011.             }
  1012.  
  1013.             //envio mi request y espero que quede pronta
  1014.             SubscriptionRequest req = new SubscriptionRequest(parameters, SubscriptionRequest.ReqType.OptionsQuoteList);
  1015.             req = _reqManager.Submit(req);
  1016.             _reqManager.WaitServed(req, 10000);
  1017.  
  1018.             //obtengo el resultado de la request
  1019.             OptionChainResponse res = (OptionChainResponse)req.Result;
  1020.  
  1021.             if (req.RequestStatus == SubscriptionRequest.Status.Served)
  1022.             {
  1023.                 _logger.Info(string.Format("OptionChain for {0} date {1} served from Neovest", symbol, date));
  1024.             }
  1025.             else
  1026.             {
  1027.                 _logger.Info(string.Format("Timedout: OptionChain for {0} date {1}", symbol, date));
  1028.             }
  1029.             //convierto la cadena de opciones en un arreglo de optionPairs
  1030.             OptionPair[] ret = createOptPairsFromChain(res);
  1031.             return ret;
  1032.         }
  1033.  
  1034.         public OptionPair[] GetOptionChainNTM(string symbol, string date, int count)
  1035.         {
  1036.             //declaro variables iniciales
  1037.             Dictionary<string, string> parameters = new Dictionary<string, string>();
  1038.             int i = 1;
  1039.             string ticker;
  1040.             var culture = CultureInfo.InvariantCulture;
  1041.             DateTime fecha;
  1042.             Stopwatch stopwatch = new Stopwatch();
  1043.  
  1044.             if (!DateTime.TryParseExact(date, "MMMyy;yyyy-MM-dd;yyyyMMdd".Split(';'), culture, DateTimeStyles.None, out fecha))
  1045.                 throw new ApplicationException("date format not supported.");
  1046.  
  1047.             string key = symbol + "-" + fecha + "NTM";
  1048.             string[] tickers; //para guardar la lista de tickers que devuelve mi "cache"
  1049.  
  1050.             if (_optionChains.TryGetValue(key, out tickers))// si es esta en la cache, entonces no es necesario pedir los datos a yahoo nuevamente.
  1051.             {
  1052.                 _logger.Info(string.Format("Obtenidas de Yahoo: {0}", tickers.Length));
  1053.                 foreach (string s in tickers)
  1054.                 {
  1055.                     ticker = s;
  1056.                     parameters.Add("Ticker" + i.ToString(), ticker);
  1057.                     i++;
  1058.                 }
  1059.             }
  1060.             else //si no estaba en mi "cache", entonces pido los datos a yahoo! y los guardo en un nuevo registro de mi diccionario cache.
  1061.             {
  1062.                 List<string> tckrs = new List<string>();//para mi cache
  1063.  
  1064.                 OptionPair[] optionChainYahoo = _yahooQuotesProvider.GetOptionChainNTM(symbol, date, count);
  1065.  
  1066.                 //convierto los nombres a "native" para que neovest los entienda
  1067.                 foreach (OptionPair opt in optionChainYahoo)
  1068.                 {
  1069.                     if ((opt.CallTicker != null) && (opt.PutTicker != null))
  1070.                     {
  1071.                         //Para verificar que es un call (dado que yahoo a veces se confunde y manda puts por calls y viceversa. Es decir, un optionPair con dos calls o dos puts. Pasa con AA-20191005)
  1072.                         string callTicker = transformarTipoDeTicker(opt.CallTicker, 'C');
  1073.                         ticker = nativeSymbol(callTicker);
  1074.                         parameters.Add("Ticker" + i.ToString(), ticker);
  1075.                         tckrs.Add(ticker);//para mi cache
  1076.                         i++;
  1077.  
  1078.                         //Para verificar que es un put (dado que yahoo a veces se confunde y manda puts por calls y viceversa. Es decir, un optionPair con dos calls o dos puts. Pasa con AA-20191005)
  1079.                         string putTicker = transformarTipoDeTicker(opt.PutTicker, 'P');
  1080.                         ticker = nativeSymbol(putTicker);
  1081.                         parameters.Add("Ticker" + i.ToString(), ticker);
  1082.                         tckrs.Add(ticker);//para mi cache
  1083.                         i++;
  1084.                     }
  1085.                     else if ((opt.CallTicker != null) && (opt.PutTicker == null))
  1086.                     {
  1087.                         ticker = nativeSymbol(opt.CallTicker);
  1088.                        
  1089.                         parameters.Add("Ticker" + i.ToString(), ticker);
  1090.                         tckrs.Add(ticker);//para mi cache
  1091.                         i++;
  1092.  
  1093.                         string putTicker = transformarTipoDeTicker(opt.CallTicker, 'P');
  1094.                         ticker = nativeSymbol(putTicker);
  1095.                         parameters.Add("Ticker" + i.ToString(), ticker);
  1096.                         tckrs.Add(ticker);//para mi cache
  1097.                         i++;
  1098.                     }
  1099.                     else if ((opt.CallTicker == null) && (opt.PutTicker != null))
  1100.                     {
  1101.                         string callTicker = transformarTipoDeTicker(opt.PutTicker, 'C');
  1102.                         ticker = nativeSymbol(callTicker);
  1103.                         parameters.Add("Ticker" + i.ToString(), ticker);
  1104.                         tckrs.Add(ticker);//para mi cache
  1105.                         i++;
  1106.  
  1107.                         ticker = nativeSymbol(opt.PutTicker);
  1108.                         parameters.Add("Ticker" + i.ToString(), ticker);
  1109.                         tckrs.Add(ticker);//para mi cache
  1110.                         i++;
  1111.                     }
  1112.                 }
  1113.                 _logger.Info(string.Format("Obtenidas de Yahoo: {0}", tckrs.Count()));
  1114.                 _optionChains.TryAdd(key, tckrs.ToArray());//los guardo en un nuevo registro de mi diccionario cache.
  1115.             }
  1116.  
  1117.             //envio mi request y espero que quede pronta
  1118.             SubscriptionRequest req = new SubscriptionRequest(parameters, SubscriptionRequest.ReqType.OptionsQuoteList);
  1119.  
  1120.             req = _reqManager.Submit(req);
  1121.             _reqManager.WaitServed(req, 10000);
  1122.             if (req.RequestStatus == SubscriptionRequest.Status.Served)
  1123.             {
  1124.                 _logger.Info(string.Format("OptionChainNTM for {0} date {1} served from Neovest", symbol, date));
  1125.             }
  1126.             else
  1127.             {
  1128.                 _logger.Info(string.Format("Timedout: OptionChainNTM for {0} date {1}", symbol, date));
  1129.             }
  1130.  
  1131.             OptionChainResponse res;
  1132.             OptionPair[] ret;
  1133.             //if (req.RequestStatus == SubscriptionRequest.Status.Served)
  1134.             //{
  1135.             // obtengo el resultado de la request
  1136.             res = (OptionChainResponse)req.Result;
  1137.  
  1138.             //convierto la cadena de opciones en un arreglo de optionPairs
  1139.             ret = createOptPairsFromChain(res);
  1140.             //}
  1141.             //else
  1142.             //{
  1143.             //    throw new Exception($"Request no servida. Status: {req.RequestStatus}");
  1144.             //}
  1145.  
  1146.             return ret;
  1147.         }
  1148.  
  1149.  
  1150.         public OptionChainResponse GetOptionChain(string symbol, string date)
  1151.         {
  1152.             //declaro variables iniciales
  1153.             Dictionary<string, string> parameters = new Dictionary<string, string>();
  1154.             int i = 1;
  1155.             string ticker;
  1156.             var culture = CultureInfo.InvariantCulture;
  1157.             DateTime fecha;
  1158.  
  1159.             if (!DateTime.TryParseExact(date, "MMMyy;yyyy-MM-dd;yyyyMMdd".Split(';'), culture, DateTimeStyles.None, out fecha))
  1160.                 throw new ApplicationException("date format not supported.");
  1161.  
  1162.             string key = symbol + "-" + fecha;
  1163.             string[] tickers; //para guardar la lista de tickers que devuelve mi "cache"
  1164.  
  1165.             if (_optionChains.TryGetValue(key, out tickers))// si es esta en la cache, entonces no es necesario pedir los datos a yahoo nuevamente.
  1166.             {
  1167.                 foreach (string s in tickers)
  1168.                 {
  1169.                     ticker = s;
  1170.                     parameters.Add("Ticker" + i.ToString(), ticker);
  1171.                     i++;
  1172.                 }
  1173.             }
  1174.             else //si no estaba en mi "cache", entonces pido los datos a yahoo! y los guardo en un nuevo registro de mi diccionario cache.
  1175.             {
  1176.                 List<string> tckrs = new List<string>();//para mi cache
  1177.  
  1178.                 OptionChainResponse optionChainResponseYahoo = _yahooQuotesProvider.GetOptionChain(symbol, date);
  1179.  
  1180.                 //convierto los nombres a "native" para que neovest los entienda
  1181.                 foreach (Option opt in optionChainResponseYahoo.Puts)
  1182.                 {
  1183.                     ticker = nativeSymbol(opt.Ticker);
  1184.                     parameters.Add("ticker" + i.ToString(), ticker);
  1185.                     tckrs.Add(ticker);//para mi cache
  1186.                     i++;
  1187.                 }
  1188.                 foreach (Option opt in optionChainResponseYahoo.Calls)
  1189.                 {
  1190.                     ticker = nativeSymbol(opt.Ticker);
  1191.                     parameters.Add("ticker" + i.ToString(), ticker);
  1192.                     tckrs.Add(ticker);//para mi cache
  1193.                     i++;
  1194.                 }
  1195.  
  1196.                 _optionChains.TryAdd(key, tckrs.ToArray());//los guardo en un nuevo registro de mi diccionario cache.
  1197.             }
  1198.             //envio mi request y espero que quede pronta
  1199.             SubscriptionRequest req = new SubscriptionRequest(parameters, SubscriptionRequest.ReqType.OptionsQuoteList);
  1200.             req = _reqManager.Submit(req);
  1201.             _reqManager.WaitServed(req, 10000);
  1202.             if (req.RequestStatus == SubscriptionRequest.Status.Served)
  1203.             {
  1204.                 _logger.Info(string.Format("OptionChain for {0} date {1} served from Neovest", symbol, date));
  1205.             }
  1206.             else
  1207.             {
  1208.                 _logger.Info(string.Format("Timedout: OptionChain for {0} date {1}", symbol, date));
  1209.             }
  1210.  
  1211.             //obtengo el resultado de la request
  1212.             OptionChainResponse ret = (OptionChainResponse)req.Result;
  1213.             return ret;
  1214.         }
  1215.  
  1216.         public string[] GetOptionContracts(string symbol, string format)
  1217.         {
  1218.             throw new NotImplementedException();
  1219.         }
  1220.  
  1221.         public Option GetOptionQuote(string symbol)
  1222.         {
  1223.             throw new NotImplementedException();
  1224.         }
  1225.  
  1226.         public Stock GetStockQuote(string symbol)
  1227.         {
  1228.             //<Nuevo>
  1229.             //envio mi request y espero que quede servida
  1230.             Dictionary<string, string> parameters = new Dictionary<string, string>();
  1231.             parameters.Add("symbol", nativeSymbol(symbol));
  1232.             SubscriptionRequest req = new SubscriptionRequest(parameters, SubscriptionRequest.ReqType.StockQuote);
  1233.             Stopwatch stopwatch = new Stopwatch();
  1234.             stopwatch.Start();
  1235.             req = _reqManager.Submit(req);
  1236.             _reqManager.WaitServed(req, 10000);
  1237.  
  1238.             //obtengo el resultado de la request
  1239.             List<Stock> stocks = (List<Stock>)req.Result;
  1240.             Stock stock = stocks[0];
  1241.             //if (stock != null)
  1242.             //{
  1243.             //    _logger.Info(string.Format("Stock quotes served from Neovest in {0}", stopwatch.Elapsed));
  1244.             //}
  1245.             //else
  1246.             //{
  1247.             //    _logger.Info(string.Format("Stock quotes request Timed Out, {0} seconds elapsed", stopwatch.Elapsed));
  1248.             //}
  1249.             return stock;
  1250.  
  1251.             //</Nuevo>
  1252.         }
  1253.  
  1254.         public SymbolGuide[] GetSymbolGuide(string symbol, int start, int count)
  1255.         {
  1256.             throw new NotImplementedException();
  1257.         }
  1258.  
  1259.         public double GetVAR(string symbol)
  1260.         {
  1261.             throw new NotImplementedException();
  1262.         }
  1263.  
  1264.         public bool IsAvailable()
  1265.         {
  1266.             throw new NotImplementedException();
  1267.         }
  1268.  
  1269.         public void RemoveFromSymbolGuide(string symbol)
  1270.         {
  1271.             throw new NotImplementedException();
  1272.         }
  1273.  
  1274.         public void Start()
  1275.         {
  1276.  
  1277.         }
  1278.  
  1279.         public void Stop()
  1280.         {
  1281.             throw new NotImplementedException();
  1282.         }
  1283.  
  1284.         public void UpdateSymbolGuide(SymbolGuide entry)
  1285.         {
  1286.             throw new NotImplementedException();
  1287.         }
  1288.  
  1289.         private void handleUpdate(UpdateMessage msg)
  1290.         {
  1291.             var delta = _accumulatedUpdates.ContainsKey(msg.Ticker) ? msg.getDiff(_accumulatedUpdates[msg.Ticker]) : msg;
  1292.             _accumulatedUpdates.AddOrUpdate(msg.Ticker, msg, (k, o) => o.Update(delta));
  1293.             if (OnQuoteUpdate != null && delta.HasAnyValue)
  1294.                 OnQuoteUpdate(new UpdateMessage[] { delta });
  1295.         }
  1296.  
  1297.         public void Subscribe(string[] symbols)
  1298.         {
  1299.             Dictionary<string, string> symbolsNeovest = new Dictionary<string, string>();
  1300.  
  1301.             int i = 1;
  1302.             foreach (string s in symbols)
  1303.             {
  1304.                 symbolsNeovest.Add("Ticker" + i.ToString(), nativeSymbol(s));
  1305.                 i++;
  1306.             }
  1307.  
  1308.             SubscriptionRequest req = new SubscriptionRequest(symbolsNeovest, SubscriptionRequest.ReqType.QuotesSubscription);
  1309.             req = _reqManager.Submit(req);
  1310.             _reqManager.WaitServed(req, 10000);//wip
  1311.             if(req.RequestStatus == SubscriptionRequest.Status.Served)
  1312.             {
  1313.                 List<UpdateMessage> mensajes = (List<UpdateMessage>)req.Result;
  1314.                 foreach (UpdateMessage updMsg in mensajes)
  1315.                 {
  1316.                     if (updMsg.HasAnyValue)
  1317.                         handleUpdate(updMsg);
  1318.                 }
  1319.             }
  1320.             else
  1321.             {
  1322.                 _logger.Info("Request Timedout");
  1323.             }
  1324.         }
  1325.  
  1326.         private void DoQuotesSubscription(string[] symbols, SubscriptionRequest req)
  1327.         {
  1328.             requestData(symbols, new GenericListener((si, sre) =>
  1329.             {
  1330.                 if (sre.getStatus() == SymbolRecordEvent.SUCCESS)
  1331.                 {
  1332.                     var symbolrecord = sre.getSymbolRecord();
  1333.                     var updMsg = new UpdateMessage();
  1334.                     var symbol = NeovestQuotesProvider.standardSymbol(si.getDisplayString());
  1335.                     //var exchange = symbolrecord.getExchangeCode().getExchangeName();
  1336.  
  1337.                     switch (sre.getEventType())
  1338.                     {
  1339.                         case SymbolRecordEvent.TRADE_CHANGES:
  1340.                         case SymbolRecordEvent.BID_CHANGES:
  1341.                         case SymbolRecordEvent.ASK_CHANGES:
  1342.                         case SymbolRecordEvent.PCLOSE_CHANGES:
  1343.                         case SymbolRecordEvent.NEW_HIGH_CHANGES:
  1344.                         case SymbolRecordEvent.NEW_LOW_CHANGES:
  1345.                         case SymbolRecordEvent.SYMBOL_COMPLETE:
  1346.  
  1347.  
  1348.                             updMsg.Ticker = symbol;
  1349.  
  1350.                             updMsg.Ask = symbolrecord.getAsk();
  1351.                             updMsg.Bid = symbolrecord.getBid();
  1352.                             updMsg.Change = symbolrecord.getNet();
  1353.                             updMsg.High = symbolrecord.getHigh();
  1354.                             updMsg.Last = symbolrecord.getLast();
  1355.                             updMsg.Close = symbolrecord.getPClose();
  1356.                             updMsg.Low = symbolrecord.getLow();
  1357.                             updMsg.Open = symbolrecord.getOpen();
  1358.                             updMsg.Volume = symbolrecord.getVolume();
  1359.  
  1360.                             _updates.AddOrUpdate(symbol, updMsg, (s, u) => u );//wip
  1361.                             //if (updMsg.HasAnyValue)
  1362.                             //    handleUpdate(updMsg);
  1363.                             break;
  1364.  
  1365.                         //case SymbolRecordEvent.GENERAL_CHANGES:
  1366.                         //    break;
  1367.  
  1368.  
  1369.                         default:
  1370.                             break;
  1371.                     }
  1372.                     lock (req)
  1373.                     {
  1374.                         if (!req.State.ContainsKey(symbol))
  1375.                         {
  1376.                             req.State.Add(symbol, "OK");
  1377.                         }
  1378.                         if ((req.RequestStatus != SubscriptionRequest.Status.Served) && (req.State.Count == symbols.Length))
  1379.                         {
  1380.                             List<UpdateMessage> mensajes = new List<UpdateMessage>();
  1381.                             foreach (string s in symbols)
  1382.                             {
  1383.                                 string standardSym = standardSymbol(s);
  1384.                                 UpdateMessage message;
  1385.                                 _updates.TryGetValue(standardSym, out message);
  1386.                                 mensajes.Add(message);
  1387.                             }
  1388.                             req.Result = mensajes;
  1389.                             _reqManager.SetServed(req);
  1390.                         }
  1391.                     }
  1392.                 }
  1393.             }), false);
  1394.         }
  1395.  
  1396.         public void Unsubscribe(string[] symbols)
  1397.         {
  1398.             Dictionary<string, string> symbolsNeovest = new Dictionary<string, string>();
  1399.  
  1400.             int i = 1;
  1401.             foreach (string s in symbols)
  1402.             {
  1403.                 symbolsNeovest.Add("Ticker" + i.ToString(), nativeSymbol(s));
  1404.                 i++;
  1405.             }
  1406.  
  1407.             SubscriptionRequest req = new SubscriptionRequest(symbolsNeovest, SubscriptionRequest.ReqType.QuotesUnsubscription);
  1408.             req = _reqManager.Submit(req);
  1409.             _reqManager.WaitServed(req, 10000);
  1410.  
  1411.         }
  1412.  
  1413.         private void DoQuotesUnsubscription(string[] symbols, SubscriptionRequest req)
  1414.         {
  1415.             foreach (string symbol in symbols)
  1416.             {
  1417.                 SymbolSubcriptionKey subscriptionKey;
  1418.                 _subscriptionKeys.TryGetValue(symbol, out subscriptionKey);
  1419.                 _logger.Info(string.Format("Desubscribiendose para el ticker: {0}, SubscriptionKey: {1}", symbol, subscriptionKey));
  1420.                 _service.unsubscribeSymbol(subscriptionKey);
  1421.                 //var symbolInfo = new SymbologyInfo(symbol);
  1422.                 //_service.unsubscribeSymbol(symbolInfo, new GenericListener((si, sre) =>
  1423.                 //{
  1424.                 //    if (sre.getStatus() == SymbolRecordEvent.SUCCESS)
  1425.                 //    {
  1426.                 //        var ticker = si.getSymbologySymbolString();
  1427.  
  1428.                 //        if (!req.State.ContainsKey(ticker))
  1429.                 //        {
  1430.                 //            req.State.Add(ticker, "OK");
  1431.                 //        }
  1432.                 //        if ((req.RequestStatus != SubscriptionRequest.Status.Served) && (req.State.Count == symbols.Length))
  1433.                 //        {
  1434.                 //            lock (req)
  1435.                 //            {
  1436.                 //                _reqManager.SetServed(req);
  1437.                 //            }
  1438.                 //        }
  1439.                 //    }
  1440.                 //}), );
  1441.             }
  1442.  
  1443.         }
  1444.     }
  1445. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement