def test_malformed(): expected = { 'BeginString': 'FIX.4.2', 'BodyLength': '156', 'CheckSum': '228', 'MsgSeqNum': '2', 'MsgType': 'J', 'NoAllocs': [{ 'AllocAccount': 'Marcin', 'AllocShares': '10', 'NoMiscFees': [{ 'MiscFeeAmt': '7.99' }] }, { 'AllocAccount': 'Jason', 'AllocShares': '5' }], 'NoOrders': [{ 'ClOrdID': 'C11111', 'OrderID': 'O11111' }, { 'ClOrdID': 'C22222', 'OrderID': 'O22222' }, { 'OrderID': 'O33333' }], 'SenderCompID': 'PXMD', 'SendingTime': '20140922-14:48:49.825', 'TargetCompID': 'Q037' } _expected = expected.copy() # this one is good formatted = '''8=FIX.4.2|9=156|35=J|49=PXMD|56=Q037|34=2|52=20140922-14:48:49.825|73=3|11=C11111|37=O11111|11=C22222|37=O22222|37=O33333|78=2|79=Marcin|80=10|136=1|137=7.99|79=Jason|80=5|10=228|''' assert parse_message(formatted) == expected, pprint( parse_message(formatted)) # ||||| formatted = '''8=FIX.4.2|9=156|35=J|49=PXMD|56=Q037|34=2|52=20140922-14:48:49.825|73=3|11=C11111|37=O11111|11=C22222|37=O22222|37=O33333|78=2|79=Marcin|80=10|136=1|137=7.99|||||79=Jason|80=5|10=228|''' assert parse_message(formatted) == expected, pprint( parse_message(formatted)) # |a|a|a|a| formatted = '''8=FIX.4.2|9=156|35=J|49=PXMD|56=Q037|34=2|52=20140922-14:48:49.825|73=3|11=C11111|37=O11111|11=C22222|37=O22222|37=O33333|78=2|79=Marcin|80=10|136=1|137=7.99|a|a|a|a|79=Jason|80=5|10=228|''' assert parse_message(formatted) == expected, pprint( parse_message(formatted)) # |=| formatted = '''8=FIX.4.2|9=156|35=J|49=PXMD|56=Q037|34=2|52=20140922-14:48:49.825|73=3|11=C11111|37=O11111|11=C22222|37=O22222|37=O33333|78=2|79=Marcin|80=10|136=1|137=7.99|=|79=Jason|80=5|10=228|''' assert parse_message(formatted) == expected, pprint( parse_message(formatted)) # |==|=| formatted = '''8=FIX.4.2|9=156|35=J|49=PXMD|56=Q037|34=2|52=20140922-14:48:49.825|73=3|11=C11111|37=O11111|11=C22222|37=O22222|37=O33333|78=2|79=Marcin|80=10|136=1|137=7.99|==|=|79=Jason|80=5|10=228|''' assert parse_message(formatted) == expected, pprint( parse_message(formatted)) # |22|=| formatted = '''8=FIX.4.2|9=156|35=J|49=PXMD|56=Q037|34=2|52=20140922-14:48:49.825|73=3|11=C11111|37=O11111|11=C22222|37=O22222|37=O33333|78=2|79=Marcin|80=10|136=1|137=7.99|22|=|79=Jason|80=5|10=228|''' assert parse_message(formatted) == expected, pprint( parse_message(formatted)) # |=asdf| formatted = '''8=FIX.4.2|9=156|35=J|49=PXMD|56=Q037|34=2|52=20140922-14:48:49.825|73=3|11=C11111|37=O11111|11=C22222|37=O22222|37=O33333|78=2|79=Marcin|80=10|136=1|137=7.99|=asdf|79=Jason|80=5|10=228|''' assert parse_message(formatted) == expected, pprint( parse_message(formatted)) # |A=A| (not a digit) formatted = '''8=FIX.4.2|9=156|35=J|49=PXMD|56=Q037|34=2|52=20140922-14:48:49.825|73=3|11=C11111|37=O11111|11=C22222|37=O22222|37=O33333|78=2|79=Marcin|80=10|136=1|137=7.99|A=A|79=Jason|80=5|10=228|''' assert parse_message(formatted) == expected, pprint( parse_message(formatted)) # || formatted = '''8=FIX.4.2|9=156|35=J|49=PXMD|56=Q037|34=2|52=20140922-14:48:49.825|73=3|11=C11111|37=O11111|11=C22222|37=O22222|37=O33333|78=2|79=Marcin|80=10|136=1|137=7.99|22||79=Jason|80=5|10=228|''' assert parse_message(formatted) == expected, pprint( parse_message(formatted)) # |9001=12345| formatted = '''8=FIX.4.2|9=156|35=J|49=PXMD|56=Q037|34=2|9001=12345|52=20140922-14:48:49.825|73=3|11=C11111|37=O11111|11=C22222|37=O22222|37=O33333|78=2|79=Marcin|80=10|136=1|137=7.99|79=Jason|80=5|10=228|''' expected['Field9001'] = '12345' assert parse_message(formatted) == expected, pprint( parse_message(formatted)) del expected['Field9001'] # note, we still don't have a test where the group breaks by a rogue tag mid-group # is that something necessary? at that point, it's pretty badly broken. # Bad BeginString 8=FIX. formatted = '''8=FIX.|9=156|35=J|49=PXMD|56=Q037|34=2|52=20140922-14:48:49.825|73=3|11=C11111|37=O11111|11=C22222|37=O22222|37=O33333|78=2|79=Marcin|80=10|136=1|137=7.99|79=Jason|80=5|10=228|''' original = expected.pop('BeginString') assert parse_message(formatted) == dict(expected, BeginString='FIX.'), pprint( parse_message(formatted)) # put BeginString back expected['BeginString'] = original # note, we chop off the CheckSum here because we're gonna mess it up badly formatted = '''8=FIX.4.2|9=156|35=X|49=PXMD|56=Q037|34=2|52=20140922-14:48:49.825|73=3|11=C11111|37=O11111|11=C22222|37=O22222|37=O33333|78=2|79=Marcin|80=10|136=1|137=7.99|79=Jason|80=5|''' checksum = expected.pop('CheckSum') # update MsgType expected['MsgType'] = 'X' assert parse_message(formatted) != expected, pprint( parse_message(formatted)) assert parse_message(formatted, cls=FIX.FIX42.Allocation) == expected, pprint( parse_message(formatted)) # put those fields back to how they were expected['MsgType'] = 'J' expected['CheckSum'] = checksum expected = { 'BeginString': 'FIX.4.2', 'BodyLength': '74', 'CheckSum': '213', 'EncryptMethod': '1', 'HeartBtInt': '3503', 'MsgType': 'A', 'RawData': 'AAAAAAAAAAAAAAAA\001AAA', 'RawDataLength': '20', 'SendingTime': '20150407-04:12:54.885' } # we're messing with Logon RawData and RawDataLength, disparity between purpoted length and data # behavior should observe the length field, and ignore bytes unaccounted for # RawDataLength < len(RawData) expected['RawDataLength'] = '17' formatted = '8=FIX.4.2\0019=74\00135=A\00152=20150407-04:12:54.885\00198=1\001108=3503\00195=%s\00196=AAAAAAAAAAAAAAAA\001AAA\00110=213\001' % ( expected['RawDataLength'], ) assert parse_message(formatted) == expected, pprint( parse_message(formatted)) # RawDataLength > len(RawData) # We lose CheckSum tag to RawData expected[ 'RawDataLength'] = '23' #TODO should we not expect to handle overlylong values here? expected['RawData'] = 'AAAAAAAAAAAAAAAA\001AAA\00110=213' expected.pop('CheckSum') formatted = '8=FIX.4.2\0019=74\00135=A\00152=20150407-04:12:54.885\00198=1\001108=3503\00195=%s\00196=AAAAAAAAAAAAAAAA\001AAA\00110=213\001' % ( expected['RawDataLength'], ) assert parse_message(formatted) == expected, pprint( parse_message(formatted))
def test_parser(): expected = { 'BeginString': 'FIX.4.2', 'BodyLength': '295', 'CheckSum': '215', 'MsgSeqNum': '2', 'MsgType': 'i', 'NoQuoteSets': [{ 'NoQuoteEntries': [{ 'BidSize': '1000000', 'BidSpotRate': '1.4363', 'OfferSize': '900000', 'OfferSpotRate': '1.4365', 'QuoteEntryID': '0' }, { 'BidSize': '7000000', 'BidSpotRate': '1.4363', 'OfferSize': '800000', 'OfferSpotRate': '1.4365', 'QuoteEntryID': '1' }], 'QuoteSetID': '123' }, { 'NoQuoteEntries': [{ 'BidSize': '1000000', 'BidSpotRate': '1.4363', 'OfferSize': '900000', 'OfferSpotRate': '1.4365', 'QuoteEntryID': '2' }, { 'BidSize': '7000000', 'BidSpotRate': '1.4363', 'OfferSize': '800000', 'OfferSpotRate': '1.4365', 'QuoteEntryID': '3' }], 'QuoteSetID': '234' }], 'QuoteID': '1', 'SenderCompID': 'PXMD', 'SendingTime': '20140922-14:48:49.825', 'TargetCompID': 'Q037' } formatted = '''8=FIX.4.2|9=295|35=i|49=PXMD|56=Q037|34=2|52=20140922-14:48:49.825|117=1|296=2|302=123|295=2|299=0|134=1000000|135=900000|188=1.4363|190=1.4365|299=1|134=7000000|135=800000|188=1.4363|190=1.4365|302=234|295=2|299=2|134=1000000|135=900000|188=1.4363|190=1.4365|299=3|134=7000000|135=800000|188=1.4363|190=1.4365|10=215|''' assert parse_message(formatted) == expected, pprint( parse_message(formatted)) message = FIX.FIX42.MassQuote(**expected) assert repr(message) == formatted message = FIX.FIXMessage(**expected) assert repr(message) == formatted fromstring = FIX.FIX42.MassQuote.fromstring(formatted) assert repr(fromstring) == formatted fromstring = FIX.FIXMessage.fromstring(formatted) assert repr(fromstring) == formatted # since this is going to mess up the CheckSum and change the MsgType # field as rendered in the formatted string, let's account for that fromstring = FIX.FIX42.MassQuote.fromstring(formatted, MsgType='A') assert repr(fromstring)[:-4] == formatted.replace('35=i', '35=A')[:-4] assert isinstance(fromstring, FIX.FIX42.MassQuote) assert not isinstance(fromstring, FIX.FIX42.Logon) fromstring = FIX.FIXMessage.fromstring(formatted, MsgType='A') #assert repr(fromstring)[:-4] == formatted.replace('35=i', '35=A')[:-4] assert isinstance(fromstring, FIX.FIX42.Logon) expected = { 'BeginString': 'FIX.4.2', 'BodyLength': '156', 'CheckSum': '228', 'MsgSeqNum': '2', 'MsgType': 'J', 'NoAllocs': [{ 'AllocAccount': 'Marcin', 'AllocShares': '10', 'NoMiscFees': [{ 'MiscFeeAmt': '7.99' }] }, { 'AllocAccount': 'Jason', 'AllocShares': '5' }], 'NoOrders': [{ 'ClOrdID': 'C11111', 'OrderID': 'O11111' }, { 'ClOrdID': 'C22222', 'OrderID': 'O22222' }, { 'OrderID': 'O33333' }], 'SenderCompID': 'PXMD', 'SendingTime': '20140922-14:48:49.825', 'TargetCompID': 'Q037' } formatted = '''8=FIX.4.2|9=156|35=J|49=PXMD|56=Q037|34=2|52=20140922-14:48:49.825|73=3|11=C11111|37=O11111|11=C22222|37=O22222|37=O33333|78=2|79=Marcin|80=10|136=1|137=7.99|79=Jason|80=5|10=228|''' assert parse_message(formatted) == expected, pprint( parse_message(formatted)) message = FIX.FIX42.Allocation(**expected) assert repr(message) == formatted message = FIX.FIXMessage(**expected) assert repr(message) == formatted fromstring = FIX.FIX42.Allocation.fromstring(formatted) assert repr(fromstring) == formatted fromstring = FIX.FIXMessage.fromstring(formatted) assert repr(fromstring) == formatted expected = { 'BeginString': 'FIX.4.2', 'BodyLength': '182', 'CheckSum': '005', 'MsgSeqNum': '2', 'MsgType': 'J', 'NoAllocs': [ { 'AllocAccount': 'Marcin', 'AllocShares': '10', 'NoMiscFees': [{ 'MiscFeeAmt': '7.99' }] }, { 'AllocAccount': 'Jason', 'AllocShares': '5' }, { 'AllocShares': '10' }, { 'AllocAccount': 'Tester' }, ], 'NoOrders': [{ 'ClOrdID': 'C11111', 'OrderID': 'O11111' }, { 'ClOrdID': 'C22222', 'OrderID': 'O22222' }, { 'OrderID': 'O33333' }, { 'ClOrdID': 'O44444' }], 'SenderCompID': 'PXMD', 'SendingTime': '20140922-14:48:49.825', 'TargetCompID': 'Q037' } formatted = '8=FIX.4.2|9=182|35=J|49=PXMD|56=Q037|34=2|52=20140922-14:48:49.825|73=4|11=C11111|37=O11111|11=C22222|37=O22222|37=O33333|11=O44444|78=4|79=Marcin|80=10|136=1|137=7.99|79=Jason|80=5|80=10|79=Tester|10=005|' assert parse_message(formatted) == expected, pprint( parse_message(formatted)) message = FIX.FIX42.Allocation(**expected) assert repr(message) == formatted message = FIX.FIXMessage(**expected) assert repr(message) == formatted fromstring = FIX.FIX42.Allocation.fromstring(formatted) assert repr(fromstring) == formatted fromstring = FIX.FIXMessage.fromstring(formatted) assert repr(fromstring) == formatted #FIX.register_version('phixlib/spec/FIX50SP2.xml') #fromstring = FIX.FIX50.AllocationInstruction.fromstring(formatted, BeginString='FIX.5.0') #assert repr(fromstring)[9:-7] == formatted[9:-7] #print repr(fromstring) ''' expected = { 'BeginString': 'FIX.4.2', 'BodyLength': '197', 'CheckSum': '225', 'MsgSeqNum': '2', 'MsgType': 'BBBBBBBBBBBBBBBB', 'NoAllocs': [{'AllocAccount': 'Marcin', 'AllocShares': '10', 'NoMiscFees': [{'MiscFeeAmt': '7.99'}]}, {'AllocAccount': 'Jason', 'AllocShares': '5'}, {'AllocShares': '10'}, {'AllocAccount': 'Tester'}, ], 'NoOrders': [{'ClOrdID': 'C11111', 'OrderID': 'O11111'}, {'ClOrdID': 'C22222', 'OrderID': 'O22222'}, {'OrderID': 'O33333'}, {'ClOrdID': 'O44444'}], 'SenderCompID': 'PXMD', 'SendingTime': '20140922-14:48:49.825', 'TargetCompID': 'Q037'} message.header._initialized['MsgType'].value = 'BBBBBBBBBBBBBBBB' formatted = '8=FIX.4.2|9=197|35=BBBBBBBBBBBBBBBB|49=PXMD|56=Q037|34=2|52=20140922-14:48:49.825|73=4|11=C11111|37=O11111|11=C22222|37=O22222|37=O33333|11=O44444|78=4|79=Marcin|80=10|136=1|137=7.99|79=Jason|80=5|80=10|79=Tester|10=225|' assert parse_message(formatted) == expected, pprint(parse_message(formatted)) ''' expected = { 'BeginString': 'FIX.4.2', 'BodyLength': '74', 'CheckSum': '213', 'EncryptMethod': '1', 'HeartBtInt': '3503', 'MsgType': 'A', 'RawData': 'AAAAAAAAAAAAAAAA\001AAA', 'RawDataLength': '20', 'SendingTime': '20150407-04:12:54.885' } formatted = '8=FIX.4.2\0019=74\00135=A\00152=20150407-04:12:54.885\00198=1\001108=3503\00195=20\00196=AAAAAAAAAAAAAAAA\001AAA\00110=213\001' assert parse_message(formatted) == expected, pprint( parse_message(formatted)) fromstring = FIX.FIX42.Logon.fromstring(formatted) assert str(fromstring) == formatted
def test_initialize(): m = FIX.FIX42.NewOrderSingle() m.initialize() for field in m._all.itervalues(): if field.required: assert field in m assert m.get(field).value, field.name + ' not initialized' expected = { 'BeginString': 'FIX.4.2', 'BodyLength': '312', 'CheckSum': '206', 'MsgSeqNum': '2', 'MsgType': 'i', 'NoQuoteSets': [{ 'NoQuoteEntries': [{ 'BidSize': '1000000', 'BidSpotRate': '1.4363', 'OfferSize': '900000', 'OfferSpotRate': '1.4365', 'QuoteEntryID': '0' }, { 'BidSize': '7000000', 'BidSpotRate': '1.4363', 'OfferSize': '800000', 'OfferSpotRate': '1.4365', 'QuoteEntryID': '1' }], 'QuoteSetID': '123' }, { 'NoQuoteEntries': [{ 'BidSize': '1000000', 'BidSpotRate': '1.4363', 'OfferSize': '900000', 'OfferSpotRate': '1.4365', 'QuoteEntryID': '2' }, { 'BidSize': '7000000', 'BidSpotRate': '1.4363', 'OfferSize': '800000', 'OfferSpotRate': '1.4365', 'QuoteEntryID': '3' }], 'QuoteSetID': '234' }], 'QuoteID': '1', 'SenderCompID': 'PXMD', 'SendingTime': '20140922-14:48:49.825', 'Signature': 'TestSignature', 'TargetCompID': 'Q037' } data = {'NoQuoteSets': expected.pop('NoQuoteSets')} data['SendingTime'] = expected.pop('SendingTime') data['Signature'] = expected.pop('Signature') m = FIX.FIX42.MassQuote(**expected) m.initialize(**data) for field in m._all.itervalues(): if field.required: assert field.name in m assert m.get(field).value, field.name + ' not initialized' # don't assert repr/str, as intialize order will be different # also, we can't achieve 100% code coverage with this test as we'd need # to supply optional=True expected.update(data) assert parse_message(str(m)) == expected, pprint(parse_message(str(m))) m = FIX.FIX42.Logon() m.initialize(HeartBtInt=60, optional=True) for field in m.header._all: if field in ( 'BeginString', 'BodyLength', 'SenderCompID', 'TargetCompID', 'MsgSeqNum', ): continue assert field in m.header._initialized for field in m._all: assert field in m._initialized for field in m.trailer._all: if field == 'CheckSum': continue assert field in m.trailer._initialized assert m.get(FIX.FIX42.Logon.HeartBtInt).value == 60
def test_initialize(): m = FIX.FIX42.NewOrderSingle() m.initialize() for field in m._all.itervalues(): if field.required: assert field in m assert m.get(field).value, field.name + " not initialized" expected = { "BeginString": "FIX.4.2", "BodyLength": "312", "CheckSum": "206", "MsgSeqNum": "2", "MsgType": "i", "NoQuoteSets": [ { "NoQuoteEntries": [ { "BidSize": "1000000", "BidSpotRate": "1.4363", "OfferSize": "900000", "OfferSpotRate": "1.4365", "QuoteEntryID": "0", }, { "BidSize": "7000000", "BidSpotRate": "1.4363", "OfferSize": "800000", "OfferSpotRate": "1.4365", "QuoteEntryID": "1", }, ], "QuoteSetID": "123", }, { "NoQuoteEntries": [ { "BidSize": "1000000", "BidSpotRate": "1.4363", "OfferSize": "900000", "OfferSpotRate": "1.4365", "QuoteEntryID": "2", }, { "BidSize": "7000000", "BidSpotRate": "1.4363", "OfferSize": "800000", "OfferSpotRate": "1.4365", "QuoteEntryID": "3", }, ], "QuoteSetID": "234", }, ], "QuoteID": "1", "SenderCompID": "PXMD", "SendingTime": "20140922-14:48:49.825", "Signature": "TestSignature", "TargetCompID": "Q037", } data = {"NoQuoteSets": expected.pop("NoQuoteSets")} data["SendingTime"] = expected.pop("SendingTime") data["Signature"] = expected.pop("Signature") m = FIX.FIX42.MassQuote(**expected) m.initialize(**data) for field in m._all.itervalues(): if field.required: assert field.name in m assert m.get(field).value, field.name + " not initialized" # don't assert repr/str, as intialize order will be different # also, we can't achieve 100% code coverage with this test as we'd need # to supply optional=True expected.update(data) assert parse_message(str(m)) == expected, pprint(parse_message(str(m))) m = FIX.FIX42.Logon() m.initialize(HeartBtInt=60, optional=True) for field in m.header._all: if field in ("BeginString", "BodyLength", "SenderCompID", "TargetCompID", "MsgSeqNum"): continue assert field in m.header._initialized for field in m._all: assert field in m._initialized for field in m.trailer._all: if field == "CheckSum": continue assert field in m.trailer._initialized assert m.get(FIX.FIX42.Logon.HeartBtInt).value == 60
def test_malformed(): expected = { "BeginString": "FIX.4.2", "BodyLength": "156", "CheckSum": "228", "MsgSeqNum": "2", "MsgType": "J", "NoAllocs": [ {"AllocAccount": "Marcin", "AllocShares": "10", "NoMiscFees": [{"MiscFeeAmt": "7.99"}]}, {"AllocAccount": "Jason", "AllocShares": "5"}, ], "NoOrders": [ {"ClOrdID": "C11111", "OrderID": "O11111"}, {"ClOrdID": "C22222", "OrderID": "O22222"}, {"OrderID": "O33333"}, ], "SenderCompID": "PXMD", "SendingTime": "20140922-14:48:49.825", "TargetCompID": "Q037", } _expected = expected.copy() # this one is good formatted = """8=FIX.4.2|9=156|35=J|49=PXMD|56=Q037|34=2|52=20140922-14:48:49.825|73=3|11=C11111|37=O11111|11=C22222|37=O22222|37=O33333|78=2|79=Marcin|80=10|136=1|137=7.99|79=Jason|80=5|10=228|""" assert parse_message(formatted) == expected, pprint(parse_message(formatted)) # ||||| formatted = """8=FIX.4.2|9=156|35=J|49=PXMD|56=Q037|34=2|52=20140922-14:48:49.825|73=3|11=C11111|37=O11111|11=C22222|37=O22222|37=O33333|78=2|79=Marcin|80=10|136=1|137=7.99|||||79=Jason|80=5|10=228|""" assert parse_message(formatted) == expected, pprint(parse_message(formatted)) # |a|a|a|a| formatted = """8=FIX.4.2|9=156|35=J|49=PXMD|56=Q037|34=2|52=20140922-14:48:49.825|73=3|11=C11111|37=O11111|11=C22222|37=O22222|37=O33333|78=2|79=Marcin|80=10|136=1|137=7.99|a|a|a|a|79=Jason|80=5|10=228|""" assert parse_message(formatted) == expected, pprint(parse_message(formatted)) # |=| formatted = """8=FIX.4.2|9=156|35=J|49=PXMD|56=Q037|34=2|52=20140922-14:48:49.825|73=3|11=C11111|37=O11111|11=C22222|37=O22222|37=O33333|78=2|79=Marcin|80=10|136=1|137=7.99|=|79=Jason|80=5|10=228|""" assert parse_message(formatted) == expected, pprint(parse_message(formatted)) # |==|=| formatted = """8=FIX.4.2|9=156|35=J|49=PXMD|56=Q037|34=2|52=20140922-14:48:49.825|73=3|11=C11111|37=O11111|11=C22222|37=O22222|37=O33333|78=2|79=Marcin|80=10|136=1|137=7.99|==|=|79=Jason|80=5|10=228|""" assert parse_message(formatted) == expected, pprint(parse_message(formatted)) # |22|=| formatted = """8=FIX.4.2|9=156|35=J|49=PXMD|56=Q037|34=2|52=20140922-14:48:49.825|73=3|11=C11111|37=O11111|11=C22222|37=O22222|37=O33333|78=2|79=Marcin|80=10|136=1|137=7.99|22|=|79=Jason|80=5|10=228|""" assert parse_message(formatted) == expected, pprint(parse_message(formatted)) # |=asdf| formatted = """8=FIX.4.2|9=156|35=J|49=PXMD|56=Q037|34=2|52=20140922-14:48:49.825|73=3|11=C11111|37=O11111|11=C22222|37=O22222|37=O33333|78=2|79=Marcin|80=10|136=1|137=7.99|=asdf|79=Jason|80=5|10=228|""" assert parse_message(formatted) == expected, pprint(parse_message(formatted)) # |A=A| (not a digit) formatted = """8=FIX.4.2|9=156|35=J|49=PXMD|56=Q037|34=2|52=20140922-14:48:49.825|73=3|11=C11111|37=O11111|11=C22222|37=O22222|37=O33333|78=2|79=Marcin|80=10|136=1|137=7.99|A=A|79=Jason|80=5|10=228|""" assert parse_message(formatted) == expected, pprint(parse_message(formatted)) # || formatted = """8=FIX.4.2|9=156|35=J|49=PXMD|56=Q037|34=2|52=20140922-14:48:49.825|73=3|11=C11111|37=O11111|11=C22222|37=O22222|37=O33333|78=2|79=Marcin|80=10|136=1|137=7.99|22||79=Jason|80=5|10=228|""" assert parse_message(formatted) == expected, pprint(parse_message(formatted)) # |9001=12345| formatted = """8=FIX.4.2|9=156|35=J|49=PXMD|56=Q037|34=2|9001=12345|52=20140922-14:48:49.825|73=3|11=C11111|37=O11111|11=C22222|37=O22222|37=O33333|78=2|79=Marcin|80=10|136=1|137=7.99|79=Jason|80=5|10=228|""" expected["Field9001"] = "12345" assert parse_message(formatted) == expected, pprint(parse_message(formatted)) del expected["Field9001"] # note, we still don't have a test where the group breaks by a rogue tag mid-group # is that something necessary? at that point, it's pretty badly broken. # Bad BeginString 8=FIX. formatted = """8=FIX.|9=156|35=J|49=PXMD|56=Q037|34=2|52=20140922-14:48:49.825|73=3|11=C11111|37=O11111|11=C22222|37=O22222|37=O33333|78=2|79=Marcin|80=10|136=1|137=7.99|79=Jason|80=5|10=228|""" original = expected.pop("BeginString") assert parse_message(formatted) == dict(expected, BeginString="FIX."), pprint(parse_message(formatted)) # put BeginString back expected["BeginString"] = original # note, we chop off the CheckSum here because we're gonna mess it up badly formatted = """8=FIX.4.2|9=156|35=X|49=PXMD|56=Q037|34=2|52=20140922-14:48:49.825|73=3|11=C11111|37=O11111|11=C22222|37=O22222|37=O33333|78=2|79=Marcin|80=10|136=1|137=7.99|79=Jason|80=5|""" checksum = expected.pop("CheckSum") # update MsgType expected["MsgType"] = "X" assert parse_message(formatted) != expected, pprint(parse_message(formatted)) assert parse_message(formatted, cls=FIX.FIX42.Allocation) == expected, pprint(parse_message(formatted)) # put those fields back to how they were expected["MsgType"] = "J" expected["CheckSum"] = checksum expected = { "BeginString": "FIX.4.2", "BodyLength": "74", "CheckSum": "213", "EncryptMethod": "1", "HeartBtInt": "3503", "MsgType": "A", "RawData": "AAAAAAAAAAAAAAAA\001AAA", "RawDataLength": "20", "SendingTime": "20150407-04:12:54.885", } # we're messing with Logon RawData and RawDataLength, disparity between purpoted length and data # behavior should observe the length field, and ignore bytes unaccounted for # RawDataLength < len(RawData) expected["RawDataLength"] = "17" formatted = ( "8=FIX.4.2\0019=74\00135=A\00152=20150407-04:12:54.885\00198=1\001108=3503\00195=%s\00196=AAAAAAAAAAAAAAAA\001AAA\00110=213\001" % (expected["RawDataLength"],) ) assert parse_message(formatted) == expected, pprint(parse_message(formatted)) # RawDataLength > len(RawData) # We lose CheckSum tag to RawData expected["RawDataLength"] = "23" # TODO should we not expect to handle overlylong values here? expected["RawData"] = "AAAAAAAAAAAAAAAA\001AAA\00110=213" expected.pop("CheckSum") formatted = ( "8=FIX.4.2\0019=74\00135=A\00152=20150407-04:12:54.885\00198=1\001108=3503\00195=%s\00196=AAAAAAAAAAAAAAAA\001AAA\00110=213\001" % (expected["RawDataLength"],) ) assert parse_message(formatted) == expected, pprint(parse_message(formatted))
def test_parser(): expected = { "BeginString": "FIX.4.2", "BodyLength": "295", "CheckSum": "215", "MsgSeqNum": "2", "MsgType": "i", "NoQuoteSets": [ { "NoQuoteEntries": [ { "BidSize": "1000000", "BidSpotRate": "1.4363", "OfferSize": "900000", "OfferSpotRate": "1.4365", "QuoteEntryID": "0", }, { "BidSize": "7000000", "BidSpotRate": "1.4363", "OfferSize": "800000", "OfferSpotRate": "1.4365", "QuoteEntryID": "1", }, ], "QuoteSetID": "123", }, { "NoQuoteEntries": [ { "BidSize": "1000000", "BidSpotRate": "1.4363", "OfferSize": "900000", "OfferSpotRate": "1.4365", "QuoteEntryID": "2", }, { "BidSize": "7000000", "BidSpotRate": "1.4363", "OfferSize": "800000", "OfferSpotRate": "1.4365", "QuoteEntryID": "3", }, ], "QuoteSetID": "234", }, ], "QuoteID": "1", "SenderCompID": "PXMD", "SendingTime": "20140922-14:48:49.825", "TargetCompID": "Q037", } formatted = """8=FIX.4.2|9=295|35=i|49=PXMD|56=Q037|34=2|52=20140922-14:48:49.825|117=1|296=2|302=123|295=2|299=0|134=1000000|135=900000|188=1.4363|190=1.4365|299=1|134=7000000|135=800000|188=1.4363|190=1.4365|302=234|295=2|299=2|134=1000000|135=900000|188=1.4363|190=1.4365|299=3|134=7000000|135=800000|188=1.4363|190=1.4365|10=215|""" assert parse_message(formatted) == expected, pprint(parse_message(formatted)) message = FIX.FIX42.MassQuote(**expected) assert repr(message) == formatted message = FIX.FIXMessage(**expected) assert repr(message) == formatted fromstring = FIX.FIX42.MassQuote.fromstring(formatted) assert repr(fromstring) == formatted fromstring = FIX.FIXMessage.fromstring(formatted) assert repr(fromstring) == formatted # since this is going to mess up the CheckSum and change the MsgType # field as rendered in the formatted string, let's account for that fromstring = FIX.FIX42.MassQuote.fromstring(formatted, MsgType="A") assert repr(fromstring)[:-4] == formatted.replace("35=i", "35=A")[:-4] assert isinstance(fromstring, FIX.FIX42.MassQuote) assert not isinstance(fromstring, FIX.FIX42.Logon) fromstring = FIX.FIXMessage.fromstring(formatted, MsgType="A") # assert repr(fromstring)[:-4] == formatted.replace('35=i', '35=A')[:-4] assert isinstance(fromstring, FIX.FIX42.Logon) expected = { "BeginString": "FIX.4.2", "BodyLength": "156", "CheckSum": "228", "MsgSeqNum": "2", "MsgType": "J", "NoAllocs": [ {"AllocAccount": "Marcin", "AllocShares": "10", "NoMiscFees": [{"MiscFeeAmt": "7.99"}]}, {"AllocAccount": "Jason", "AllocShares": "5"}, ], "NoOrders": [ {"ClOrdID": "C11111", "OrderID": "O11111"}, {"ClOrdID": "C22222", "OrderID": "O22222"}, {"OrderID": "O33333"}, ], "SenderCompID": "PXMD", "SendingTime": "20140922-14:48:49.825", "TargetCompID": "Q037", } formatted = """8=FIX.4.2|9=156|35=J|49=PXMD|56=Q037|34=2|52=20140922-14:48:49.825|73=3|11=C11111|37=O11111|11=C22222|37=O22222|37=O33333|78=2|79=Marcin|80=10|136=1|137=7.99|79=Jason|80=5|10=228|""" assert parse_message(formatted) == expected, pprint(parse_message(formatted)) message = FIX.FIX42.Allocation(**expected) assert repr(message) == formatted message = FIX.FIXMessage(**expected) assert repr(message) == formatted fromstring = FIX.FIX42.Allocation.fromstring(formatted) assert repr(fromstring) == formatted fromstring = FIX.FIXMessage.fromstring(formatted) assert repr(fromstring) == formatted expected = { "BeginString": "FIX.4.2", "BodyLength": "182", "CheckSum": "005", "MsgSeqNum": "2", "MsgType": "J", "NoAllocs": [ {"AllocAccount": "Marcin", "AllocShares": "10", "NoMiscFees": [{"MiscFeeAmt": "7.99"}]}, {"AllocAccount": "Jason", "AllocShares": "5"}, {"AllocShares": "10"}, {"AllocAccount": "Tester"}, ], "NoOrders": [ {"ClOrdID": "C11111", "OrderID": "O11111"}, {"ClOrdID": "C22222", "OrderID": "O22222"}, {"OrderID": "O33333"}, {"ClOrdID": "O44444"}, ], "SenderCompID": "PXMD", "SendingTime": "20140922-14:48:49.825", "TargetCompID": "Q037", } formatted = "8=FIX.4.2|9=182|35=J|49=PXMD|56=Q037|34=2|52=20140922-14:48:49.825|73=4|11=C11111|37=O11111|11=C22222|37=O22222|37=O33333|11=O44444|78=4|79=Marcin|80=10|136=1|137=7.99|79=Jason|80=5|80=10|79=Tester|10=005|" assert parse_message(formatted) == expected, pprint(parse_message(formatted)) message = FIX.FIX42.Allocation(**expected) assert repr(message) == formatted message = FIX.FIXMessage(**expected) assert repr(message) == formatted fromstring = FIX.FIX42.Allocation.fromstring(formatted) assert repr(fromstring) == formatted fromstring = FIX.FIXMessage.fromstring(formatted) assert repr(fromstring) == formatted # FIX.register_version('phixlib/spec/FIX50SP2.xml') # fromstring = FIX.FIX50.AllocationInstruction.fromstring(formatted, BeginString='FIX.5.0') # assert repr(fromstring)[9:-7] == formatted[9:-7] # print repr(fromstring) """ expected = { 'BeginString': 'FIX.4.2', 'BodyLength': '197', 'CheckSum': '225', 'MsgSeqNum': '2', 'MsgType': 'BBBBBBBBBBBBBBBB', 'NoAllocs': [{'AllocAccount': 'Marcin', 'AllocShares': '10', 'NoMiscFees': [{'MiscFeeAmt': '7.99'}]}, {'AllocAccount': 'Jason', 'AllocShares': '5'}, {'AllocShares': '10'}, {'AllocAccount': 'Tester'}, ], 'NoOrders': [{'ClOrdID': 'C11111', 'OrderID': 'O11111'}, {'ClOrdID': 'C22222', 'OrderID': 'O22222'}, {'OrderID': 'O33333'}, {'ClOrdID': 'O44444'}], 'SenderCompID': 'PXMD', 'SendingTime': '20140922-14:48:49.825', 'TargetCompID': 'Q037'} message.header._initialized['MsgType'].value = 'BBBBBBBBBBBBBBBB' formatted = '8=FIX.4.2|9=197|35=BBBBBBBBBBBBBBBB|49=PXMD|56=Q037|34=2|52=20140922-14:48:49.825|73=4|11=C11111|37=O11111|11=C22222|37=O22222|37=O33333|11=O44444|78=4|79=Marcin|80=10|136=1|137=7.99|79=Jason|80=5|80=10|79=Tester|10=225|' assert parse_message(formatted) == expected, pprint(parse_message(formatted)) """ expected = { "BeginString": "FIX.4.2", "BodyLength": "74", "CheckSum": "213", "EncryptMethod": "1", "HeartBtInt": "3503", "MsgType": "A", "RawData": "AAAAAAAAAAAAAAAA\001AAA", "RawDataLength": "20", "SendingTime": "20150407-04:12:54.885", } formatted = "8=FIX.4.2\0019=74\00135=A\00152=20150407-04:12:54.885\00198=1\001108=3503\00195=20\00196=AAAAAAAAAAAAAAAA\001AAA\00110=213\001" assert parse_message(formatted) == expected, pprint(parse_message(formatted)) fromstring = FIX.FIX42.Logon.fromstring(formatted) assert str(fromstring) == formatted