为人类提供的pythonic金融信息交换(fix)客户端。
wtfix的Python项目详细描述
wtfix
为人类提供的pythonic金融信息交换(fix)客户端。
项目重点和目标
为Python3从头开始构建。
包括电池-提供连接到修复服务器并开始发送和接收所需的一切 以分钟为单位的消息。提供以下项的默认实现:
- 身份验证
- 保持心跳
- 序列号管理和重新发送请求
- 消息存储和检索
基于现代
async and await
实现的快速、易于理解的消息处理管道。易于扩展的体系结构-模块化的“应用程序”可以添加到管道堆栈中以添加自定义消息处理 例程或新的应用程序功能。
PIPELINE_APPS=["my_app.apps.SecretAlgoTradingRecipe",# <-- Your application logic"wtfix.apps.api.RESTfulServiceApp",# REST API for sending messages"wtfix.apps.brokers.RedisPubSubApp",# Redis Pub/Sub broker for sending / receiving messages"wtfix.apps.admin.HeartbeatApp",# Heartbeat monitoring and maintenance"wtfix.apps.admin.AuthenticationApp",# Login / logout handling"wtfix.apps.admin.SeqNumManagerApp",# Message gap detection and filling"wtfix.apps.store.MessageStoreApp",# Store messages (caching or persistence)"wtfix.apps.utils.InboundLoggingApp",# Log inbound messages"wtfix.apps.parsers.RawMessageParserApp",# Message parsing: Logon (A): {BeginString (8): FIX.4.4 | BodyLength (9): 99 | MsgType (35): A | MsgSeqNum (34): 1 | SenderCompID (49): SENDER | SendingTime (52): 20190305-08:45:45.979 | TargetCompID (56): TARGET | EncryptMethod (98): 0 | HeartBtInt (108): 30 | Username (553): USERNAME | Password (554): PASSWORD | ResetSeqNumFlag (141): Y | CheckSum (10): 94}"wtfix.apps.utils.OutboundLoggingApp",# Log outbound messages"wtfix.apps.wire.WireCommsApp",# Raw message encoding / decoding: b'8=FIX.4.4\x019=99\x0135=A\x0134=1\x0149=SENDER\x0152=20190305-08:42:32.793\x0156=TARGET\x0198=0\x01108=30\x01553=USERNAME\x01554=PASSWORD\x01141=Y\x0110=081\x01'"wtfix.apps.sessions.ClientSessionApp",# HTTP session management]
消息可以缓存在内存中,也可以保存到redis消息存储中供以后检索。或者您可以添加 您自己的消息存储解决方案使用提供的接口。
直接从管道、通过使用rest api的第三方应用程序或通过将消息发布到 用于立即交付的redis发布/子频道。
提供一个方便的
@on
装饰器,用于细粒度控制哪些应用程序将响应哪些类型的消息:fromwtfix.apps.baseimportMessageTypeHandlerApp,onfromwtfix.protocol.commonimportMsgTypefromwtfix.confimportsettingslogger=settings.loggerclassSecretAlgoTradingRecipe(MessageTypeHandlerApp):@on(MsgType.Logon)# Only invoked when 'Logon (type A)' messages are received.defon_logon(self,message):self.send_security_definition_request()returnmessagedefon_receive(self,message):# Invoked for every type of message.logger.info(f"Received message {message}!")
提供自定义的
Field
和FieldMap
类型,用于处理固定标记和字段值。这些类型是“Python型”, 实现许多标准协议,并在将它们集成到现有Python中时表现出人意料 代码。一种简单的消息标记语法,具有各种方便的方法,用于快速访问 已使用的消息属性。
>>>fromwtfix.messageimportadmin>>>fromwtfix.protocol.commonimportTag# Instantiate a new 'Logon' message>>>logon_msg=admin.LogonMessage("my_username","my_password",heartbeat_int=30)# Short, concise string representation>>>str(logon_msg)'A: {(35, A) | (98, 0) | (108, 30) | (553, my_username) | (554, my_password)}'# Pretty print tag names by using the 't' formatting option>>>f"{logon_msg:t}"'Logon (A): {MsgType (35): A | EncryptMethod (98): 0 | HeartBtInt (108): 30 | Username (553): my_username | Password (554): my_password}'# Example of getting the message type>>>logon_msg.type'A'# Example of getting the message type name>>>logon_msg.name'Logon'# Look up the sequence number>>>logon_msg.seq_num1# Various ways for accessing the different fields that make up the message. Fields are just# (tag, value) namedtuples.>>>logon_msg[108]# Using old school tag numberField(108,'30')>>>logon_msg[Tag.HeartBtInt]# Using the tag name as per the FIX specificationField(108,'30')>>>logon_msg.HeartBtInt# Using tag name shortcutField(108,'30')
一种基于实用unicode sandwich的编译码方法 消息意味着您不需要直接处理字节序列。
fromwtfix.message.fieldimportFieldfromwtfix.message.messageimportgeneric_message_factory# Create a new Message from a byte sequence received over the wire>>>fields=Field.fields_frombytes(b"35=A\x0198=0\x01108=30\x01553=my_username\x01554=my_password\x01")>>>logon_msg=generic_message_factory(*fields)>>>str(logon_msg)'A: {(35, A) | (98, 0) | (108, 30) | (553, my_username) | (554, my_password)}'# Fields are tuples of (tag, value) pairs>>>username=logon_msg.Username>>>username.tag553>>>username.value"my_username"# Fields behave just like Python's built-in types, and most operations can be performed directly# on a field's 'value' attribute.>>>username+="_123">>>usernameField(553,'my_username_123')
需要时访问底层字节序列:
>>>bytes(logon_msg)b'35=A\x0198=0\x01108=30\x01553=my_username\x01554=my_password\x01'
向消息添加字段很容易:只需分配标记值即可:
>>>logon_msg.PossDupFlag="Y">>>f"{logon_msg:t}"'Logon (A): {MsgType (35): A | EncryptMethod (98): 0 | HeartBtInt (108): 30 | Username (553): my_username | Password (554): my_password | PossDupFlag (43): Y}'# Most FIX field values can be cast to their corresponding Python built-in type>>>bool(logon_msg.PossDupFlag)isTrueTrue
一种非常宽容的重复消息标记组的方法:
fromwtfix.protocol.commonimportTag,MsgTypefromwtfix.message.messageimportgeneric_message_factory# If you provide a group template, then messages are stored in an 'OrderedDict' for fast lookups>>>msg=generic_message_factory((Tag.MsgType,MsgType.ExecutionReport),(Tag.NoMiscFees,2),(Tag.MiscFeeAmt,10.00),(Tag.MiscFeeType,2),(Tag.MiscFeeAmt,20.00),(Tag.MiscFeeType,"A"),group_templates={Tag.NoMiscFees:[Tag.MiscFeeAmt,Tag.MiscFeeType,]})>>>msg.dataOrderedDict([(35,Field(35,'8')),(136,Group(Field(136,'2'),Field(137,'10.0'),Field(139,'2'),Field(137,'20.0'),Field(139,'A')))])# Get 'NoMiscFees' group>>>group=msg.NoMiscFees>>>f"{group:t}"'[NoMiscFees (136): 2] | [MiscFeeAmt (137): 10.0 | MiscFeeType (139): 2] | [MiscFeeAmt (137): 20.0 | MiscFeeType (139): A]'# Determine the number of instances in the group>>>group.size2# Retrieve the second group instance>>>group.instances[1]FieldList(Field(137,'20.0'),Field(139,'A'))# Without a pre-defined group template, WTFIX falls back to using a (slightly slower) list structure for representing message fields internally>>>msg=generic_message_factory((Tag.MsgType,MsgType.ExecutionReport),(Tag.NoMiscFees,2),(Tag.MiscFeeAmt,10.00),(Tag.MiscFeeType,2),(Tag.MiscFeeAmt,20.00),(Tag.MiscFeeType,"A"))>>>msg.data[Field(35,'8'),Field(136,'2'),Field(137,'10.0'),Field(139,'2'),Field(137,'20.0'),Field(139,'A')]
开始
最好在python虚拟环境中安装项目的依赖项(例如
pip install -r requirements/local.txt
) 专门为此目的而创造的环境。使用
pytest
运行测试套件以验证安装。在项目的根目录中创建至少包含以下配置设置的
.env
文件:# Supports different configuration settings for local development, staging, or production environments.WTFIX_SETTINGS_MODULE=config.settings.localHOST=# Required. The FIX server hostname or IP addressPORT=# Required. The port on the FIX server to connect toSENDER=# Required. SENDER_COMP_ID (tag 49).TARGETD=# Required. TARGET_COMP_ID (tag 56).USERNAME=# Required. Username to use for Logon messages (tag 553).PASSWORD=# Required. Password to use for logon messages (tag 554).PYTHONASYNCIODEBUG=0# Set to '1' for detailed debugging messages.
使用
python runclient.py
启动修复客户端。默认实现将登录到fix服务器并保持稳定的心跳。使用
Ctrl-C
退出。这将触发在管道终止之前发送的Logout
消息。