C#에서 WebSocket을 통해 가격 스트림을 가져옵니다.

 

안녕. 다양한 출처(LMAX 환전소 포함)로부터 견적을 받는 데 관심이 있었습니다. 서로 다른 브로커가 서로 다른 ECN, 유동성 공급자에 연결되어 있으므로 ECN 자체에서 직접 견적을 받는 것이 좋습니다. 그러나 한계가 있습니다. 대부분의 공급업체는 우리가 직접 연결할 때까지 견적을 공유하지 않습니다. 그러나 여전히 견적을 받을 수 있는 곳이 몇 군데 있습니다. 그리고 "시장의 깊이"로. 예를 들어, LMAX는 유동성을 https://s3-eu-west-1.amazonaws.com/lmax-widget3/website-widget-vwap.html과 같은 위젯으로 스트리밍합니다(따옴표가 없기 때문에 주말에는 비활성화됩니다. 평일에는 로고가 사라지고 유리창이 나타납니다.) 시장 깊이로 견적을 스트리밍하는 몇 가지 ECN도 있습니다.

견적은 웹 소켓을 통해 위젯으로 스트리밍됩니다. WebRequest()를 통해 직접 검색할 수 없으므로 websocket 이벤트를 구독해야 합니다. 그리고 여기 어두운 숲이 있습니다. 왜냐하면. 나는 C #과 더 많은 웹 기술에 대한 약한 (거의 NOT) 명령을 가지고 있습니다. :) 웹 소켓을 통해 데이터를 수신하는 2가지 예를 찾았지만 그 중 어느 것도 제대로 작동하지 않습니다.

예: 클라이언트를 만들고 소켓에 연결하는 것은 다음과 같습니다. 여기(위젯 소스를 파헤치고 적어도 나 자신을 위해 뭔가를 명확히 하려고 시도한 후)에서 위젯에 따옴표를 보냈지만 받지는 못했습니다. 견적을 받기 위해 서버에 어떤 요청을 보내야 하는지는 완전히 불분명합니다. 따옴표를 직접 보내면 서버에서 긍정적인 응답을 제공하고 표시됩니다. 스크린샷은 서버의 응답을 보여주고 크롬을 통해 소켓 스트림을 보면 연결에 대한 정보가 있습니다. 그리고 마켓도 활성화되면 전송된 시세를 스트림에 밀어 넣고 위젯에 표시합니다 :) 소켓을 통해 연결하는 또 다른 예가 있지만 여전히 작동하지 않습니다. 이 정도면 충분하다고 생각합니다.

누군가 위젯(mt 및 winapi 또는 C #에서 직접 mb.)에서 인용문을 추출하는 방법에 대한 아이디어가 있다면 감사할 것입니다. :)

 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;  
     }  
   }  
 }  

이 프레임에서 활성 시간 동안 견적 및 기타 정보의 흐름이 표시됩니다(예: 내 연결:

 

나는 모든 것을 이해하지 못했다. 그러나 월요일과 따옴표의 활동을 기다리자. 저도 보려고 합니다. 인용문의 다른 직접적인 출처도 흥미롭습니다. 그런데 보류 중인가요?

5~6년 전쯤 VBA 엑셀을 통해 어떤 사이트에서 실시간 정보(시장이 아닌)를 받았습니다. 자세한 내용은 지금 기억나지 않습니다. 브라우저 창을 통해 고양이에 연결했는데 정보가 있는 페이지와 상호 작용하는 스크립트가 작동했습니다. 그리고 스크립트는 이미 Excel에서 제공했습니다.

사실 흥미로운 질문입니다.

 
Yuriy Asaulenko :

나는 모든 것을 이해하지 못했다. 그러나 월요일과 따옴표의 활동을 기다리자. 나는 보려고 노력할 것이다. 인용문의 다른 직접적인 출처도 흥미롭습니다. 그런데 보류 중인가요?

5~6년 전쯤 VBA 엑셀을 통해 어떤 사이트에서 실시간 정보(시장이 아닌)를 받았습니다. 자세한 내용은 지금 기억나지 않습니다. 브라우저 창을 통해 고양이에 연결했는데 정보가 있는 페이지와 상호 작용하는 스크립트가 작동했습니다. 그리고 스크립트는 이미 Excel에서 제공되었습니다.

사실 흥미로운 질문입니다.

네, 월요일까지 기다려야 합니다. 거기에서 제안된 요청을 통해 위젯에 0을 넣을 수 있음을 즉시 알 수 있습니다. :) MT4의 따옴표와 비교할 때 지체 없이 빨리 오는 것 같습니다...

질문이 흥미롭습니다. 왜냐하면 위젯뿐만 아니라 웹 터미널에서도 가져올 수 있습니다..

 
Maxim Dmitrievsky :

질문이 흥미롭습니다. 왜냐하면 위젯뿐만 아니라 웹 터미널에서도 가져올 수 있습니다..

가능하면 개인에 다른 링크를 던지십시오. 모든 페이지에서 정보를 가져올 수 있는 것은 아닙니다. 연결 - 연결하면 데이터 형식이 Flash에서 하드와이어링됩니다. 그리고 단락.
 
LMAX에는 API가 있습니다. 위젯이 필요하지 않습니다.
 
Dmitriy Skub :
LMAX에는 API가 있습니다. 위젯이 필요하지 않습니다.
그래서 모든 것이 돈을 위한 것입니다. 공급업체의 모든 시장 날짜는 비용이 들거나 10,000의 송장
 
Yuriy Asaulenko :
가능하면 개인에 다른 링크를 던지십시오. 모든 페이지에서 정보를 가져올 수 있는 것은 아닙니다. 연결 - 연결하면 데이터 형식이 Flash에서 하드와이어링됩니다. 그리고 단락.
던졌다. 자, 확인해보자.. 원칙적으로 이 경우 소켓이 보이고, 스트림이 보인다. 데이터는 pull 된다.
 
Dmitriy Skub :
LMAX에는 API가 있습니다. 위젯이 필요하지 않습니다.
API에 계정이 필요한 것 같습니다.
 
Maxim Dmitrievsky :
던졌다. 자, 확인해보자.. 원칙적으로 이 경우 소켓이 보이고, 스트림이 보인다. 데이터는 pull 된다.
엠.비. 알려진 교환 프로토콜로 얻은 것입니다. Flash에서 얻을 수 없거나 암호화 와 유사합니다. :)
 

2번 연결 예 규칙에 따르면 소켓에 합법적으로 연결하려면 http에서 wss로 전환하는 헤더를 보낸 다음 tcp를 통해 소켓과 통신해야 합니다... 왜 그런 연결은 Socket을 통해 이루어져야 하며 WebSocket 을 통해 훨씬 더 쉽습니다. 여기서 잘못된 요청 오류가 발생합니다. 핸드셰이크가 없으며 헤더가 올바르게 채워진 것 같습니다. ssl로 연결되는 오류가 있을 수 있는데 GetStream이 아닌 GetSslstream을 받아야 합니다... ws는 보안되지 않은 연결이고 wss는 보안 연결입니다. 음, 그리고 더 많은 다른 "어쩌면", 병 없이는, 음, 아니면 당신의 도움 없이는 알아내기 어렵습니다. :) 코드 상단에는 이미 약간 수정한 원본 예제에 대한 링크가 있습니다.

 //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 :
그래서 모든 것이 돈을 위한 것입니다. 공급업체의 모든 시장 날짜는 비용이 들거나 10,000의 송장
음, 네, 그들은 탐욕스럽고 무엇을 할 수 있습니까)) 그러나 차익 거래를 원하면 api가 사용 가능한 유일한 옵션입니다.IMHO.