如何使用 C# .NET CORE 2.0 向 GDAX 发送 FIX 登录消息
How to send FIX logon message with C# .NET CORE 2.0 to GDAX
我正在尝试使用 C# 和 .Net Core 2.0 与 fix.gdax.com(文档:https://docs.gdax.com/#fix-api)建立 FIX 4.2 会话。当我尝试登录时,我收到 0 个字节作为服务器的响应。我真的不知道我哪里错了,这是代码:
private async Task ConnectToGdaxFix()
{
_socketTcpClient = new TcpClient();
_socketTcpClient.NoDelay = true;
_bufferEnd = 0;
await _socketTcpClient.ConnectAsync(_gdaxFixGateway, _gdaxFixPort);
_sslStream = new SslStream(_socketTcpClient.GetStream());
await _sslStream.AuthenticateAsClientAsync(_gdaxFixGateway);
byte[] buffer = new byte[2048];
var message = await FixSendLoginMessage();
var bytes = await _sslStream.ReadAsync(buffer, 0, buffer.Length);
}
private async Task<string> FixSendLoginMessage()
{
var sendTime = DateTime.UtcNow.ToString("yyyyMMdd-HH:mm:ss.fff");
string msgType = "A";
var messageSeqNumber = (++messageSeqNum).ToString();
var senderCompId = "apiKey";
var targetCompId = "Coinbase";
var password = "passphrase";
var accessSign = CreateAccessSign(
sendTime,
msgType,
messageSeqNumber,
senderCompId,
targetCompId,
password
);
var logonMessage = $"98=0{'\x01'}108=30{'\x01'}554={password}{'\x01'}96={accessSign}{'\x01'}8013=Y";
var headerAfter9Tag = $"35={msgType}{'\x01'}34={messageSeqNumber}{'\x01'}52={sendTime}{'\x01'}49={senderCompId}{'\x01'}56={targetCompId}";
var length = logonMessage.Length + headerAfter9Tag.Length + 1;
var messageHeader = $"8=FIX.4.2{'\x01'}9={length}{'\x01'}{headerAfter9Tag}";
var messageWithHeader = $"{messageHeader}{'\x01'}{logonMessage}{'\x01'}";
int sum = 0;
int len = messageWithHeader.Length;
for (int i = 0; i < len; i++)
{
sum += Convert.ToChar(messageWithHeader.Substring(i, 1));
}
sum = sum % 256;
var messageWithChecksum = $"{messageWithHeader}10={sum.ToString("000")}{'\x01'}";
byte[] buffer = Encoding.ASCII.GetBytes(messageWithChecksum);
await _sslStream.WriteAsync(buffer, 0, buffer.Length);
await _sslStream.FlushAsync();
return messageWithChecksum;
}
private string CreateAccessSign(
string sendingTime,
string msgType,
string msgSeqNumber,
string senderCompId,
string targetCompId,
string password
)
{
var stringToHash = string.Join('\x01', sendingTime, msgType, msgSeqNumber, senderCompId, targetCompId, password);
var privateKeyAsBytes = Encoding.UTF8.GetBytes("privateKey");
using (var hmac = new HMACSHA256(privateKeyAsBytes))
{
var signature = hmac.ComputeHash(Encoding.UTF8.GetBytes(stringToHash));
return Convert.ToBase64String(signature);
}
}
任何人都可以帮我看看登录消息或 ssl 加密有什么问题吗?
这是发送给Gdax的消息(敏感数据的字符已被替换,\x01为|以简化视图):8=FIX.4.2|9=161|35=A|34 =1|52=20180124-00:50:34.083|49=426123d789fa8e5c3782c549kj9de06e|56=Coinbase|98=0|108=30|554=outswrt|96=qkE5KPMLjn+Ef9Zgk1/kvL0Etem6bK2llINwMjOkDy9=|8013=Y|10=028
CreateAccessSign错误,privateKeyAsBytes需要使用Convert.FromBase64String:
var privateKeyAsBytes = Convert.FromBase64String("privateKey");
FixSendLoginMessage 错误,这是正确的实现:
private async Task<string> FixSendLoginMessage()
{
var sendTime = DateTime.UtcNow.ToString("yyyyMMdd-HH:mm:ss.fff");
string msgType = "A";
var messageSeqNumber = (++messageSeqNum).ToString();
var senderCompId = "apiKey";
var targetCompId = "Coinbase";
var password = "passphrase";
var accessSign = CreateAccessSign(
sendTime,
msgType,
messageSeqNumber,
senderCompId,
targetCompId,
password
);
var logonMessage = $"98=0{'\x01'}108=30{'\x01'}554={password}{'\x01'}96={accessSign}{'\x01'}8013=Y{'\x01'}";
var headerAfter9Tag = $"35={msgType}{'\x01'}34={messageSeqNumber}{'\x01'}52={sendTime}{'\x01'}49={senderCompId}{'\x01'}56={targetCompId}{'\x01'}";
var length = logonMessage.Length + headerAfter9Tag.Length;
var messageHeader = $"8=FIX.4.2{'\x01'}9={length}{'\x01'}{headerAfter9Tag}";
var messageWithHeader = $"{messageHeader}{logonMessage}";
int sum = 0;
int len = messageWithHeader.Length;
for (int i = 0; i < len; i++)
{
sum += Convert.ToChar(messageWithHeader.Substring(i, 1));
}
sum = sum % 256;
var messageWithChecksum = $"{messageWithHeader}10={sum.ToString("000")}{'\x01'}";
byte[] buffer = Encoding.ASCII.GetBytes(messageWithChecksum);
await _sslStream.WriteAsync(buffer, 0, buffer.Length);
await _sslStream.FlushAsync();
return messageWithChecksum;
}
我正在尝试使用 C# 和 .Net Core 2.0 与 fix.gdax.com(文档:https://docs.gdax.com/#fix-api)建立 FIX 4.2 会话。当我尝试登录时,我收到 0 个字节作为服务器的响应。我真的不知道我哪里错了,这是代码:
private async Task ConnectToGdaxFix()
{
_socketTcpClient = new TcpClient();
_socketTcpClient.NoDelay = true;
_bufferEnd = 0;
await _socketTcpClient.ConnectAsync(_gdaxFixGateway, _gdaxFixPort);
_sslStream = new SslStream(_socketTcpClient.GetStream());
await _sslStream.AuthenticateAsClientAsync(_gdaxFixGateway);
byte[] buffer = new byte[2048];
var message = await FixSendLoginMessage();
var bytes = await _sslStream.ReadAsync(buffer, 0, buffer.Length);
}
private async Task<string> FixSendLoginMessage()
{
var sendTime = DateTime.UtcNow.ToString("yyyyMMdd-HH:mm:ss.fff");
string msgType = "A";
var messageSeqNumber = (++messageSeqNum).ToString();
var senderCompId = "apiKey";
var targetCompId = "Coinbase";
var password = "passphrase";
var accessSign = CreateAccessSign(
sendTime,
msgType,
messageSeqNumber,
senderCompId,
targetCompId,
password
);
var logonMessage = $"98=0{'\x01'}108=30{'\x01'}554={password}{'\x01'}96={accessSign}{'\x01'}8013=Y";
var headerAfter9Tag = $"35={msgType}{'\x01'}34={messageSeqNumber}{'\x01'}52={sendTime}{'\x01'}49={senderCompId}{'\x01'}56={targetCompId}";
var length = logonMessage.Length + headerAfter9Tag.Length + 1;
var messageHeader = $"8=FIX.4.2{'\x01'}9={length}{'\x01'}{headerAfter9Tag}";
var messageWithHeader = $"{messageHeader}{'\x01'}{logonMessage}{'\x01'}";
int sum = 0;
int len = messageWithHeader.Length;
for (int i = 0; i < len; i++)
{
sum += Convert.ToChar(messageWithHeader.Substring(i, 1));
}
sum = sum % 256;
var messageWithChecksum = $"{messageWithHeader}10={sum.ToString("000")}{'\x01'}";
byte[] buffer = Encoding.ASCII.GetBytes(messageWithChecksum);
await _sslStream.WriteAsync(buffer, 0, buffer.Length);
await _sslStream.FlushAsync();
return messageWithChecksum;
}
private string CreateAccessSign(
string sendingTime,
string msgType,
string msgSeqNumber,
string senderCompId,
string targetCompId,
string password
)
{
var stringToHash = string.Join('\x01', sendingTime, msgType, msgSeqNumber, senderCompId, targetCompId, password);
var privateKeyAsBytes = Encoding.UTF8.GetBytes("privateKey");
using (var hmac = new HMACSHA256(privateKeyAsBytes))
{
var signature = hmac.ComputeHash(Encoding.UTF8.GetBytes(stringToHash));
return Convert.ToBase64String(signature);
}
}
任何人都可以帮我看看登录消息或 ssl 加密有什么问题吗?
这是发送给Gdax的消息(敏感数据的字符已被替换,\x01为|以简化视图):8=FIX.4.2|9=161|35=A|34 =1|52=20180124-00:50:34.083|49=426123d789fa8e5c3782c549kj9de06e|56=Coinbase|98=0|108=30|554=outswrt|96=qkE5KPMLjn+Ef9Zgk1/kvL0Etem6bK2llINwMjOkDy9=|8013=Y|10=028
CreateAccessSign错误,privateKeyAsBytes需要使用Convert.FromBase64String:
var privateKeyAsBytes = Convert.FromBase64String("privateKey");
FixSendLoginMessage 错误,这是正确的实现:
private async Task<string> FixSendLoginMessage()
{
var sendTime = DateTime.UtcNow.ToString("yyyyMMdd-HH:mm:ss.fff");
string msgType = "A";
var messageSeqNumber = (++messageSeqNum).ToString();
var senderCompId = "apiKey";
var targetCompId = "Coinbase";
var password = "passphrase";
var accessSign = CreateAccessSign(
sendTime,
msgType,
messageSeqNumber,
senderCompId,
targetCompId,
password
);
var logonMessage = $"98=0{'\x01'}108=30{'\x01'}554={password}{'\x01'}96={accessSign}{'\x01'}8013=Y{'\x01'}";
var headerAfter9Tag = $"35={msgType}{'\x01'}34={messageSeqNumber}{'\x01'}52={sendTime}{'\x01'}49={senderCompId}{'\x01'}56={targetCompId}{'\x01'}";
var length = logonMessage.Length + headerAfter9Tag.Length;
var messageHeader = $"8=FIX.4.2{'\x01'}9={length}{'\x01'}{headerAfter9Tag}";
var messageWithHeader = $"{messageHeader}{logonMessage}";
int sum = 0;
int len = messageWithHeader.Length;
for (int i = 0; i < len; i++)
{
sum += Convert.ToChar(messageWithHeader.Substring(i, 1));
}
sum = sum % 256;
var messageWithChecksum = $"{messageWithHeader}10={sum.ToString("000")}{'\x01'}";
byte[] buffer = Encoding.ASCII.GetBytes(messageWithChecksum);
await _sslStream.WriteAsync(buffer, 0, buffer.Length);
await _sslStream.FlushAsync();
return messageWithChecksum;
}