Cómo enviar un mensaje de inicio de sesión FIX con Python a GDAX / Coinbase

Estoy tratando de establecer una sesión FIX 4.2 para arreglar.gdax.com (docs:https://docs.gdax.com/#fix-api ohttps://docs.prime.coinbase.com/?python#logon-a) usando Python 3.5 y stunnel. Todo funciona aparte de mi mensaje de inicio de sesión que se rechaza y el servidor cierra la sesión sin respuesta, lo que dificulta la depuración de lo que está mal. Mi código de Python es el siguiente:

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(("127.0.0.1", 4197)) # address and port specified in stunnel config file

# generate a signature according to the gdax protocol for signing a message:
timestamp = str(time.time())
message   = [timestamp, "A", "0", "f3e85389ffb809650c367d42b37e0a80", "Coinbase", "password-goes-here"] # these are the components of the pre-hash string as specified in the docs for a logon message
message   = bytes("|".join(message), 'utf-8') # add the field separator

hmac_key  = base64.b64decode(r"api-secret-goes-here")
signature = hmac.new(hmac_key, message, hashlib.sha256)
sign_b64  = base64.b64encode(signature.digest()).decode()
# in the above line the .decode() is not included when used to authenticate messages to the REST API and those are working successfully.
#The reason I've included it here is to allow a string to be passed into the variable 'body' below:

msgType    = "A"
t          = str(datetime.utcnow()).replace("-","").replace(" ", "-")[:-3] # format the timestamp into YYYYMMDD-HH:MM:SS.sss as per the FIX standard

body       = '34=1|52=%s|49=f3e85389ffb809650c367d42b37e0a80|56=Coinbase|98=0|108=30|554=password-goes-here|96=%s|8013=Y|' % (t, sign_b64)
bodyLength = len(body.encode('utf-8')) # length of the message in bytes
header     = '8=FIX.4.2|9=%s|35=%s|' % (bodyLength, msgType)
msg        = header + body

# generate the checksum:
def check_sum(s):
    sum = 0
    for char in msg:
        sum += ord(char)
    sum = str(sum % 256)
    while len(sum) < 3:
        sum = '0' + sum
    return sum

c_sum = check_sum(msg)
logon = msg + "10=%s" % c_sum # append the check sum onto the message
logon = logon.encode('ascii') # create a bytes object to send over the socket
print(logon)

s.sendall(logon)
print(s.recv(4096))

Los resultados de esas dos declaraciones impresas son:

b'8=FIX.4.2|9=159|35=A|34=1|52=20171104-11:13:53.331|49=f3e85389ffb809650c367d42b37e0a80|56=Coinbase|98=0|108=30|554=password-goes-here|96=G7yeX8uQqsCEhAjWDWHoBiQz9lZuoE0Q8+bLJp4XnPY=|8013=Y|10=212'
b''

Aquí hay muchas variables que podrían estar equivocadas y el proceso de prueba y error se está volviendo un poco tedioso. ¿Alguien puede ver lo que está mal con el mensaje de inicio de sesión?

Respuestas a la pregunta(2)

Su respuesta a la pregunta