Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -131,3 +131,5 @@ dmypy.json
/samples/ConsoleSample/ConsoleSample-dev.py
/samples/KleinWebAppSample/credentials-dev.json
/samples/jupyter/credentials-dev.json
/samples/ConsoleSample/config-trade.json
/samples/ConsoleSample/config-quote.json
48 changes: 14 additions & 34 deletions ctrader_fix/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,20 @@

from twisted.internet.endpoints import clientFromString
from twisted.application.internet import ClientService
from messages import *
from factory import Factory
from twisted.internet import reactor
from fixProtocol import FixProtocol
from twisted.internet import reactor
import datetime
from ctrader_fix.messages import *
from ctrader_fix.factory import Factory
from ctrader_fix.fixProtocol import FixProtocol

class Client(ClientService):
def __init__(self, host, port, ssl=False, retryPolicy=None, clock=None, prepareConnection=None, numberOfMessagesToSendPerSecond=5):
def __init__(self, host, port, ssl=False, delimiter = "", retryPolicy=None, clock=None, prepareConnection=None, numberOfMessagesToSendPerSecond=5):
self._runningReactor = reactor
self.numberOfMessagesToSendPerSecond = numberOfMessagesToSendPerSecond
self.delimiter = delimiter
endpoint = clientFromString(self._runningReactor, f"ssl:{host}:{port}" if ssl else f"tcp:{host}:{port}")
factory = Factory.forProtocol(FixProtocol, client=self)
super().__init__(endpoint, factory, retryPolicy=retryPolicy, clock=clock, prepareConnection=prepareConnection)
self._factory = Factory.forProtocol(FixProtocol, client=self)
super().__init__(endpoint, self._factory, retryPolicy=retryPolicy, clock=clock, prepareConnection=prepareConnection)
self._events = dict()
self._responseDeferreds = dict()
self.isConnected = False
Expand Down Expand Up @@ -45,10 +45,17 @@ def _received(self, responseMessage):
self._messageReceivedCallback(self, responseMessage)

def send(self, requestMessage):
requestMessage.delimiter = self.delimiter
diferred = self.whenConnected(failAfterFailures=1)
diferred.addCallback(lambda protocol: protocol.send(requestMessage))
return diferred

def changeMessageSequenceNumber(self, newMessageSequenceNumber):
self._factory.messageSequenceNumber = newMessageSequenceNumber

def getMessageSequenceNumber(self):
return self._factory.messageSequenceNumber

def setConnectedCallback(self, callback):
self._connectedCallback = callback

Expand All @@ -57,30 +64,3 @@ def setDisconnectedCallback(self, callback):

def setMessageReceivedCallback(self, callback):
self._messageReceivedCallback = callback


if __name__ == "__main__":
client = Client("h51.p.ctrader.com", 5202)
quoteSessionInfo = {"Username": 3279203, "Password": 3279203, "BeginString": "FIX.4.4", "SenderCompID": "demo.icmarkets.3279203", "SenderSubID": "QUOTE", "TargetCompID": "cServer", "TargetSubID": "QUOTE", "HeartBeat": 30}
tradeSessionInfo = {"Username": 3279203, "Password": 3279203, "BeginString": "FIX.4.4", "SenderCompID": "demo.icmarkets.3279203", "SenderSubID": "TRADE", "TargetCompID": "cServer", "TargetSubID": "TRADE", "HeartBeat": 30}
isMessageSent = False

def onConnected(client):
logonMessage = LogonRequest(tradeSessionInfo)
client.send(logonMessage)

def onMessageReceived(client, responseMessage):
print("Received: ", responseMessage.getMessage())
global isMessageSent
if isMessageSent is True:
return
isMessageSent = True
request = OrderStatusRequest(tradeSessionInfo)
request.ClOrdID = "A"
client.send(request)

client.setConnectedCallback(onConnected)
client.setMessageReceivedCallback(onMessageReceived)
client.startService()

reactor.run()
22 changes: 12 additions & 10 deletions ctrader_fix/factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@
from twisted.internet.protocol import ClientFactory

class Factory(ClientFactory):
def __init__(self, *args, **kwargs):
super().__init__()
self.client = kwargs['client']
self.numberOfMessagesToSendPerSecond = self.client.numberOfMessagesToSendPerSecond
def connected(self):
self.client._connected()
def disconnected(self, reason):
self.client._disconnected(reason)
def received(self, message):
self.client._received(message)
messageSequenceNumber = 0
def __init__(self, *args, **kwargs):
super().__init__()
self.client = kwargs['client']
self.delimiter = self.client.delimiter
self.numberOfMessagesToSendPerSecond = self.client.numberOfMessagesToSendPerSecond
def connected(self):
self.client._connected()
def disconnected(self, reason):
self.client._disconnected(reason)
def received(self, message):
self.client._received(message)
18 changes: 11 additions & 7 deletions ctrader_fix/fixProtocol.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
#!/usr/bin/env python

from twisted.internet.protocol import Protocol
from messages import ResponseMessage
from ctrader_fix.messages import ResponseMessage

class FixProtocol(Protocol):
_messageSequenceNumber = 0
_currentMessage = ''
def connectionMade(self):
self.factory.messageSequenceNumber = 0
super().connectionMade()
self.factory.connected()

Expand All @@ -14,11 +15,14 @@ def connectionLost(self, reason):
self.factory.disconnected(reason)

def dataReceived(self, data):
responseMessage = ResponseMessage(data.decode("ascii"))
self.factory.received(responseMessage)
dataString = data.decode("ascii")
self._currentMessage += dataString
if f"{self.factory.delimiter}10=" in dataString and dataString.endswith(self.factory.delimiter):
responseMessage = ResponseMessage(self._currentMessage, self.factory.delimiter)
self._currentMessage = ''
self.factory.received(responseMessage)

def send(self, requestMessage):
self._messageSequenceNumber += 1
messageString = requestMessage.getMessage(self._messageSequenceNumber)
print("Sending: ", messageString)
self.factory.messageSequenceNumber += 1
messageString = requestMessage.getMessage(self.factory.messageSequenceNumber)
return self.transport.write(messageString.encode("ascii"))
Loading