C# ile WebSocket üzerinden fiyat akışı almak.

 

Merhaba canım. Çeşitli kaynaklardan (LMAX döviz borsası dahil) fiyat teklifi alma konusunda bir ilgi vardı. Farklı brokerler farklı ECN'lere, likidite sağlayıcılarına bağlı olduğundan, doğrudan ECN'lerin kendisinden teklif almak daha iyidir. Ancak bir sınırlama var - çoğu tedarikçi, biz onlara doğrudan bağlanana kadar fiyat tekliflerini bizimle paylaşmayacak. Ancak yine de fiyat teklifi alabileceğiniz birkaç yer var. ve "pazarın derinliği" ile. Örneğin, LMAX likiditesini bunun gibi widget'lara aktarır https://s3-eu-west-1.amazonaws.com/lmax-widget3/website-widget-vwap.html (hiçbir alıntı olmadığı için hafta sonları etkin değildir, hafta içi logo kaybolacak ve bir bardak görünecektir). Ayrıca fiyatlarını piyasa derinliği ile aktaran birkaç ECN var.

Alıntılar, bir websocket aracılığıyla widget'a aktarılır, yani. doğrudan WebRequest() yoluyla alınamazlar, websocket olaylarına abone olmalısınız. Ve burada karanlık bir ormanım var çünkü. Zayıf (neredeyse DEĞİL) bir C# komutuna ve hatta daha fazla web teknolojisine sahibim :) Web soketleri aracılığıyla veri almanın 2 örneğini buldum, ancak hiçbiri olması gerektiği gibi çalışmıyor.

Örnek: bir istemci oluşturmak ve bir sokete bağlanmak şuna benzer. Burada (widget kaynaklarını kazdıktan ve en azından kendim için bir şeyi netleştirmeye çalıştıktan sonra), widget'a alıntılar gönderdiği, ancak almadığı ortaya çıktı :) yani. teklif almak için sunucuya hangi isteğin gönderilmesi gerektiği tamamen belirsizdir. Teklifleri kendileri gönderirseniz, sunucu olumlu bir yanıt verecek ve üzerinde görünecektir. Ekran görüntüleri sunucunun yanıtını gösterir ve ayrıca krom aracılığıyla soket akışına bakarsanız - bağlantı hakkında bilgi vardır. Ve market de aktifken gönderilen kotasyonlar stream'e alınır ve widget'ta görüntülenir :) Bir başka örnek daha var, bir soket üzerinden bağlanma ama yine de çalışmıyor, bu kadar yeter bence.

Birinin bir widget'tan (mb. doğrudan mt ve winapi'den veya C #'dan) alıntıları nasıl çıkaracağına dair bir fikri varsa, minnettar olacağım :)

 using System;
using System.Threading.Tasks;
namespace SenseConsoleApp
{
     class Program
    {
         static void Main( string [] args)
        {
            GetDocList();
            Console.ReadLine();
        }
         static async Task< string > GetDocList()
        {
             var client = new SenseWebSocketClient( new Uri( "wss://data-fix.smt-data.com/lmax" ));
            Console.WriteLine( "Connecting to Qlik Sense..." );
            Console.WriteLine( "Getting document list..." );
             var docs = await client.GetDocList();
            Console.WriteLine(docs);
             return docs;
        }
    }
}

using System;   
 using System.Net.WebSockets;  
 using System.Text;  
 using System.Threading;  
 using System.Threading.Tasks;

 namespace SenseConsoleApp  
 {
   
   public class SenseWebSocketClient  
   {  
     private ClientWebSocket _client;
    
     public Uri _senseServerURI;  
     public SenseWebSocketClient(Uri senseServerURI)  
     {  
       _client = new ClientWebSocket();
       _senseServerURI = senseServerURI;  
     }  
     public async Task< string > GetDocList()  
     {
            
       string cmd = "{\"channel\":\"/fixprof/depthmax/EURUSD\",\"data\":[\"EURUSD\",0,0,0,0,0,0,0,0,0,0,[[0,0],[0.0,0.0],[0,0],[0,0],[0,0],[0,0],[0,0],[0.0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],[[0,0],[0,0],[0,0],[0,0],[0.0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]]],\"id\":\"56kcb\"}" ;   // это строка с запросом к серверу, т.е. по факту мы отправляем на него котировки
       await _client.ConnectAsync(_senseServerURI, CancellationToken.None);  
       await SendCommand(cmd);  
       var docList = await Receive();  
       return docList;   // ответ сервера
     }  
     private async Task ConnectToSenseServer()  
     {  
       await _client.ConnectAsync(_senseServerURI, CancellationToken.None);  
     }  
     private async Task SendCommand( string jsonCmd)  
     {  
       ArraySegment< byte > outputBuffer = new ArraySegment< byte >(Encoding.UTF8.GetBytes(jsonCmd));  
       await _client.SendAsync(outputBuffer, WebSocketMessageType.Text, true , CancellationToken.None);  
     }  
     private async Task< string > Receive()  
     {  
       var receiveBufferSize = 1536 ;  
       byte [] buffer = new byte [receiveBufferSize];  
       var result = await _client.ReceiveAsync ( new ArraySegment< byte >(buffer), CancellationToken.None);  
       var resultJson = ( new UTF8Encoding()).GetString(buffer);  
       return resultJson;  
     }  
   }  
 }  

Bu çerçevede, aktif süre boyunca, alıntı akışı ve diğer bilgiler, örneğin bağlantım görüntülenir:

 

Her şeyi anlamadım. Ama Pazartesi ve tırnak aktivitesi için bekleyelim. Ben de bakmaya çalışacağım. Diğer doğrudan alıntı kaynakları da ilginçtir. Bu arada, beklemedeler mi?

Yaklaşık 5-6 yıl önce VBA Excel aracılığıyla bazı sitelerden gerçek zamanlı bilgiler (piyasa değil) aldım. Detayları şimdi hatırlamıyorum. Tarayıcı penceremden kediye bağlandım, işe yarayan bilgilerle sayfayla etkileşime giren bir komut dosyası. Ve komut dosyası zaten Excel'de verdi.

Aslında, bu ilginç bir soru.

 
Yuriy Asaulenko :

Her şeyi anlamadım. Ama Pazartesi ve tırnak aktivitesi için bekleyelim. bakmaya çalışacağım. Diğer doğrudan alıntı kaynakları da ilginçtir. Bu arada, beklemedeler mi?

Yaklaşık 5-6 yıl önce VBA Excel aracılığıyla bazı sitelerden gerçek zamanlı bilgiler (piyasa değil) aldım. Detayları şimdi hatırlamıyorum. Tarayıcı penceremden kediye bağlandım, işe yarayan bilgilerle sayfayla etkileşime giren bir komut dosyası. Ve komut dosyası zaten Excel'de verdi.

Aslında, bu ilginç bir soru.

Evet, Pazartesiye kadar beklemeniz gerekiyor. Orada, önerilen istek aracılığıyla widget'a sıfır koyabileceğinizi hemen göreceksiniz :) MT4'teki alıntılarla karşılaştırıldığında gecikmeden hızlı geliyorlar...

Soru ilginç çünkü sadece widget'lardan değil, web terminallerinden de çekebilirsiniz..

 
Maxim Dmitrievsky :

Soru ilginç çünkü sadece widget'lardan değil, web terminallerinden de çekebilirsiniz..

Mümkünse, diğer bağlantıları kişisel olarak atın. Her sayfa bilgiyi çekemez. Bağlan - bağlan ve veri formatı, örneğin Flash'ta kablolu. Ve bir paragraf.
 
LMAX'in bir API'si vardır - hiçbir widget'a gerek yoktur.
 
Dmitriy Skub :
LMAX'in bir API'si vardır - hiçbir widget'a gerek yoktur.
yani hepsi dolar için. Tedarikçiden gelen herhangi bir piyasa tarihi, paraya veya 10k'dan bir faturaya mal olur.
 
Yuriy Asaulenko :
Mümkünse, diğer bağlantıları kişisel olarak atın. Her sayfa bilgiyi çekemez. Bağlan - bağlan ve veri formatı, örneğin Flash'ta kablolu. Ve bir paragraf.
Attı. Peki bir kontrol edelim.. Prensipte soket bu durumda görünür, akım görünür.veriler çekilecektir.
 
Dmitriy Skub :
LMAX'in bir API'si vardır - hiçbir widget'a gerek yoktur.
API'nin bir hesaba ihtiyacı olduğundan şüpheleniyorum.
 
Maxim Dmitrievsky :
Attı. Peki bir kontrol edelim.. Prensipte soket bu durumda görünür, akım görünür.veriler çekilecektir.
m.b. bilinen bir değişim protokolü ile elde edilmiştir. Flash'tan alamazsınız veya kriptografiye benzer. :)
 

2 numaralı bağlantı örneği.Kurallara göre bir sokete yasal olarak bağlanmak için http'den wss'ye geçmek için başlıklar göndermeniz ve ardından soket ile tcp üzerinden iletişim kurmanız gerekiyor... Neden böyle bir şey anlamıyorum. bağlantı Socket üzerinden yapılmalı, WebSocket ile çok daha kolay çıkıyor. Burada geçersiz bir istek hatası oluşur, yani. el sıkışma yok, başlıklar doğru doldurulmuş gibi görünüyor. Bağlantı ssl ile geliyor diye bir hata olabilir ve GetStream değil GetSslstream almanız gerekiyor... ws güvenli olmayan bir bağlantıdır, wss ise güvenli bir bağlantıdır. peki, ve daha pek çok farklı "belki", bunu bir şişe olmadan, peki ya da sizin yardımınız olmadan anlamak zor :) Kodun en üstünde, zaten biraz değiştirdiğim orijinal örneğe bir bağlantı var.

 //stackoverflow.com/questions/2064641/is-there-a-websocket-client-implemented-for-net
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Text;

namespace ssoc
{
     class Program
    {
         static void Main( string [] args)
        {
            Uri LMAXuri = new Uri( "wss://data-fix.smt-data.com/lmax" ); // путь к сокету
            Dictionary< string , string > headers = new Dictionary< string , string >(); //список хедеров для передачи серверу

            headers.Add( "Host" , "data-fix.smt-data.com" );
            headers.Add( "Connection" , "Upgrade" );
            headers.Add( "Pragma" , "no-cache" );
            headers.Add( "Cache-Control" , "no-cache" );
            headers.Add( "Upgrade" , "websocket" );
            headers.Add( "Origin" , "https://s3-eu-west-1.amazonaws.com" );
            headers.Add( "Sec-WebSocket-Version" , "13" );
            headers.Add( "User-Agent" , "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36" );
            headers.Add( "Accept-Encoding" , "gzip, deflate, sdch" );
            headers.Add( "Accept-Language" , "ru-RU,ru;q=0.8,en-US;q=0.6,en;q=0.4" );
            headers.Add( "Cookie" , "connect.sid=s%3ALwAlO60b6DkqtFUZldvHp-kR.K3qfytDjKCo4cz0%2FxxHpZk1qGCyS9AWFPDv3ro2Yu%2BU" );
            headers.Add( "Sec-WebSocket-Key" , "Kd6XNibByshdJKZA8qWmDA==" );
            headers.Add( "Sec-WebSocket-Extensions" , "permessage-deflate; client_max_window_bits" );

            WebSocket ws = new WebSocket(LMAXuri);
            ws.SetHeaders(headers); // установим свои хедерыб иначе будут исп. умолчания
            ws.Connect();
             string result = ws.Recv();
            Console.WriteLine(result);
            Console.ReadLine();

        }
    }

     public class WebSocket
    {
         private Uri mUrl;
         private TcpClient mClient;
         private NetworkStream mStream;
         private bool mHandshakeComplete;
         private Dictionary< string , string > mHeaders;

         public WebSocket(Uri url)
        {
            mUrl = url;

             string protocol = mUrl.Scheme;
             if (!protocol.Equals( "ws" ) && !protocol.Equals( "wss" ))
                 throw new ArgumentException( "Unsupported protocol: " + protocol);
        }

         public void SetHeaders(Dictionary< string , string > headers)
        {
            mHeaders = headers;
        }

         public void Connect()
        {
             string host = mUrl.DnsSafeHost;
             string path = mUrl.PathAndQuery;
             string origin = "http://" + host;
            
            mClient = CreateSocket(mUrl);
            mStream = mClient.GetStream();

             int port = ((IPEndPoint)mClient.Client.RemoteEndPoint).Port;
            
             if (port != 443 )
                host = host + ":" + port;

            StringBuilder extraHeaders = new StringBuilder();
             if (mHeaders != null )
            {
                 foreach (KeyValuePair< string , string > header in mHeaders)
                    extraHeaders.Append(header.Key + ": " + header.Value + "\r\n" );
            }

             string request = "GET " + path + " HTTP/1.1\r\n" + extraHeaders.ToString() + "\r\n" ;
             byte [] sendBuffer = Encoding.UTF8.GetBytes(request);

            mStream.Write(sendBuffer, 0 , sendBuffer.Length);

            StreamReader reader = new StreamReader(mStream);
            {
                 string header = reader.ReadLine();
                Console.WriteLine(header);
                 if (!header.Equals( "HTTP/1.1 101 Web Socket Protocol Handshake" ))
                     throw new IOException( "Invalid handshake response" );

                header = reader.ReadLine();
                 if (!header.Equals( "Upgrade: WebSocket" ))
                     throw new IOException( "Invalid handshake response" );

                header = reader.ReadLine();
                 if (!header.Equals( "Connection: Upgrade" ))
                     throw new IOException( "Invalid handshake response" );
            }

            mHandshakeComplete = true ;
            Console.WriteLine( "Сервер пожал нам руку: " , mHandshakeComplete);
        }

         public void Send( string str)
        {
             if (!mHandshakeComplete)
                 throw new InvalidOperationException( "Handshake not complete" );

             byte [] sendBuffer = Encoding.UTF8.GetBytes(str);

            mStream.WriteByte( 0x00 );
            mStream.Write(sendBuffer, 0 , sendBuffer.Length);
            mStream.WriteByte( 0xff );
            mStream.Flush();
        }

         public string Recv()
        {
             if (!mHandshakeComplete)
                 throw new InvalidOperationException( "Handshake not complete" );

            StringBuilder recvBuffer = new StringBuilder();

            BinaryReader reader = new BinaryReader(mStream);
             byte b = reader.ReadByte();
             if ((b & 0x80 ) == 0x80 )
            {
                 // Skip data frame
                 int len = 0 ;
                 do
                {
                    b = ( byte )(reader.ReadByte() & 0x7f );
                    len += b * 128 ;
                } while ((b & 0x80 ) != 0x80 );

                 for ( int i = 0 ; i < len; i++)
                    reader.ReadByte();
            }

             while ( true )
            {
                b = reader.ReadByte();
                 if (b == 0xff )
                     break ;

                recvBuffer.Append(b);
            }

             return recvBuffer.ToString();
        }

         public void Close()
        {
            mStream.Dispose();
            mClient.Close();
            mStream = null ;
            mClient = null ;
        }

         private static TcpClient CreateSocket(Uri url)
        {
             string scheme = url.Scheme;
             string host = url.DnsSafeHost;

             int port = url.Port;
             if (port <= 0 )
            {
                 if (scheme.Equals( "wss" ))
                    port = 443 ;
                 else if (scheme.Equals( "ws" ))
                    port = 80 ;
                 else
                     throw new ArgumentException( "Unsupported scheme" );
            }
             if (scheme.Equals( "ws" ))
            {
                 throw new NotImplementedException( "SSL support not implemented yet" );
            }
             else
                 return new TcpClient(host, port);
        }
    }
}
 
Maxim Dmitrievsky :
yani hepsi dolar için. Tedarikçiden gelen herhangi bir piyasa tarihi, paraya veya 10k'dan bir faturaya mal olur.
Evet, açgözlüler, ne yapabilirsin)) Ama eğer arbitraj yapmak istiyorsan, o zaman api mevcut tek seçenek.