I am trying to implement the quickfix library on the binance testnet FIX API. Fix API | Binance Open Platform. I am able to successfully get a logon response by following the instructions in the documentation above, where the instruction to generate the base64 signature is written in python.
Code given in docs
import base64
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
from cryptography.hazmat.primitives.serialization import load_pem_private_key
def logon_raw_data(private_key: Ed25519PrivateKey,
sender_comp_id: str,
target_comp_id: str,
msg_seq_num: str,
sending_time: str):
"""
Computes the value of RawData (96) field in Logon<A> message.
"""
payload = chr(1).join([
'A',
sender_comp_id,
target_comp_id,
msg_seq_num,
sending_time,
])
signature = private_key.sign(payload.encode('ASCII'))
return base64.b64encode(signature).decode('ASCII')
with open('private_key.pem', 'rb') as f:
private_key = load_pem_private_key(data=f.read(),
password=None)
raw_data = logon_raw_data(private_key,
sender_comp_id='5JQmUOsm',
target_comp_id='SPOT',
msg_seq_num='1',
sending_time='20240612-08:52:21.613')
I do not know how to implement this algorithm in c++ at the moment, and manually copied the rawdata string (generated using the python script) and used setField() to add it to the logon message as shown below. This results in ‘Signature for this request is not valid’ logon reject message.
Although generating the signature requires a timestamp input, this error is not due to the time lag of copying the signature over, compiling and running the c++ program. Sending the FIX message too long after the generated timestamp would give the following error: Timestamp for this request is outside of the recvWindow.
Is this an issue specific to c++, or would implementing the hashing algorithm in c++ fix this?
void Application::toAdmin(FIX::Message &message, const FIX::SessionID &sessionID)
EXCEPT(FIX::DoNotSend) {
if (FIX::MsgType_Logon == message.getHeader().getField(FIX::FIELD::MsgType)) {
std::string rawData = "CkY08Cf3xrN4MwAdl/Kblj2aHrGxT2sS1URZ/VM0mksR1tQd6hHQ5bda0oNSIeD/JI9cwPBJ4y2R2ZcVgy7oDQ==";
message.setField(FIX::RawDataLength(88));
message.setField(FIX::RawData(rawData));
message.setField(FIX::Username("myapikey"));
message.setField(FIX::StringField(25035, "1"));
}
}
Error logs:
Message sent: (8=FIX.4.4|9=248|35=A|34=1|49=sendercompid|52=20250102-15:38:55.546|56=SPOT|95=88|96=CkY08Cf3xrN4MwAdl/Kblj2aHrGxT2sS1URZ/VM0mksR1tQd6hHQ5bda0oNSIeD/JI9cwPBJ4y2R2ZcVgy7oDQ==|98=0|108=30|141=Y|553=apikey|25035=1|10=149|)
Response: (8=FIX.4.4|9=0000131|35=3|49=SPOT|56=ryantest|34=1|52=20250102-15:38:55.774913|45=1|372=A|373=8|25016=-1022|58=Signature for this request is not valid.|10=238|