OpenApiPy

repository·main·Indexed 41 days ago

https://github.com/spotware/openapipy

An asynchronous Python client for the cTrader Open API, built on the Twisted networking framework and Protobuf for non-blocking communication. It provides the ctrader_open_api package, featuring a Client for connection management, an Auth class for OAuth2 flows, and Protobuf utilities for message serialization and deserialization.

Tokens
8.7K
Snippets
29
Records
38
Agent score
51%

What's inside OpenApiPy

  1. Understand the Console Sample execution model

    main

    The Console Sample operates using a single thread (the Python main execution thread) to handle both user input and the sending/receiving of API messages.

    Because the main thread is shared, user input commands have a timeout. If a command is not entered within the specified period, the application will block for a few seconds before resuming command acceptance.

  2. How OpenApiPy works with Twisted

    main

    OpenApiPy is an asynchronous Python package built on top of the Twisted networking engine.

    Key architectural concepts:

    • Asynchronous Execution: The library uses the Twisted reactor to handle non-blocking I/O.
    • Deferreds: Most client methods (like client.send()) return a Twisted deferred. You interact with these using .addCallback() for successful responses or .addErrback() for error handling.
    • Protobuf Integration: The package includes pre-compiled Open API message files, so you can use the generated protobuf classes directly without manual compilation.
    • Event Callbacks: You can register optional callbacks on the Client instance to handle connection lifecycle events and incoming messages.
  3. Send messages using the Client class

    main

    To send a message, first instantiate and populate the appropriate Protobuf message type. Use the client.send() method to dispatch the message.

    client.send() returns a Twisted deferred. You must attach callbacks to this deferred to handle the asynchronous response:

    • Callback: Triggered when the response message arrives. The result is the response proto message.
    • Errback: Triggered if the message send fails or an error occurs.
    # 1. Import message types
    from ctrader_open_api.messages.OpenApiCommonMessages_pb2 import *
    from ctrader_open_api.messages.OpenApiMessages_pb2 import *
    from ctrader_open_api.messages.OpenApiModelMessages_pb2 import *
    
    # 2. Create and populate the message
    applicationAuthReq = ProtoOAApplicationAuthReq()
    applicationAuthReq.clientId = "Your App Client ID"
    applicationAuthReq.clientSecret = "Your App Client secret"
    
    # 3. Send the message and handle the deferred
    deferred = client.send(applicationAuthReq)
    
    def onProtoOAApplicationAuthRes(result):
        print(f"Response received: {result}")
    
    def onError(failure):
        print(f"Error occurred: {failure}")
    
    deferred.addCallbacks(onProtoOAApplicationAuthRes, onError)
  4. Initialize the Auth class

    main

    To handle authentication workflows, create an instance of the Auth class from the ctrader_open_api package. You must provide your application's credentials and the redirect URI where users will be sent after authentication.

    from ctrader_open_api import Auth
    
    auth = Auth("Your App ID", "Your App Secret", "Your App redirect URI")
  5. Set up credentials for the Jupyter Sample

    main

    To use the Jupyter Sample, you must prepare a credentials file.

    1. Create a copy of the credentials.json file.
    2. Rename the copy to credentials-dev.json.
    3. Open credentials-dev.json and populate it with your Open API application credentials, access token, and a trading account ID.
  6. Create a Client instance

    main

    Use the Client class to interact with the cTrader Open API. Each instance manages a single connection to either a live or demo endpoint and abstracts connection/reconnection complexities using the Twisted ClientService.

    To initialize a client, provide the host, port, and protocol (typically TcpProtocol). You can also control the message rate using numberOfMessagesToSendPerSecond to comply with API limitations.

    from ctrader_open_api import Client, Protobuf, TcpProtocol, Auth, EndPoints
    
    # Create a client instance for the Demo endpoint
    client = Client(EndPoints.PROTOBUF_DEMO_HOST, EndPoints.PROTOBUF_PORT, TcpProtocol)
  7. Initialize and run the cTrader Open API Client

    main

    To use the client, you must select a host (Live or Demo), instantiate the Client with a protocol (typically TcpProtocol), set up your event callbacks, and start the Twisted reactor.

    Follow these steps:

    1. Select Host: Use EndPoints.PROTOBUF_LIVE_HOST or EndPoints.PROTOBUF_DEMO_HOST.
    2. Instantiate Client: client = Client(host, EndPoints.PROTOBUF_PORT, TcpProtocol).
    3. Set Callbacks: Use setConnectedCallback, setDisconnectedCallback, and setMessageReceivedCallback to handle events.
    4. Start Service: Call client.startService().
    5. Run Reactor: Execute reactor.run() to start the asynchronous loop.
    from ctrader_open_api import Client, Protobuf, TcpProtocol, Auth, EndPoints
    from ctrader_open_api.messages.OpenApiMessages_pb2 import *
    from twisted.internet import reactor
    
    # 1. Setup connection details
    host = EndPoints.PROTOBUF_DEMO_HOST
    client = Client(host, EndPoints.PROTOBUF_PORT, TcpProtocol)
    
    # 2. Define event handlers
    def connected(client):
        print("Connected!")
    
    def onMessageReceived(client, message):
        # Use Protobuf.extract to view the message content
        print("Message received: \n", Protobuf.extract(message))
    
    # 3. Register callbacks
    client.setConnectedCallback(connected)
    client.setMessageReceivedCallback(onMessageReceived)
    
    # 4. Start and run
    client.startService()
    reactor.run()
  8. Set up the Klein Web App Sample

    main

    The Klein Web App Sample is a web-based demonstration of the Spotware OpenApiPy Python package using the Twisted Klein web framework. To run the sample, follow these steps:

    1. Configure Credentials: Create a copy of the credentials.json file, rename it to credentials-dev.json, and populate it with your Open API application credentials.
    2. Install Dependencies: Install the Klein web framework using pip:
      pip install klein
    3. Run the Application: Execute the main.py file.
    4. Access the UI: Open http://localhost:8080 in your web browser.
    pip install klein
  9. How asynchronous execution and callbacks work in OpenApiPy

    main

    OpenApiPy is built on top of Twisted, meaning execution is asynchronous and non-sequential. You interact with the API using a callback-driven pattern:

    1. Client Callbacks: Use client.setConnectedCallback(func), client.setDisconnectedCallback(func), and client.setMessageReceivedCallback(func) to handle lifecycle events and incoming messages.
    2. Request/Response Flow: When you call client.send(request), it returns a Twisted deferred. You must attach callbacks to this deferred using .addCallbacks(onSuccess, onError) to handle the response or any errors.
    3. The Event Loop: You must call client.startService() and then reactor.run() to start the asynchronous event loop.

    Typical Workflow Example:

    • connected callback triggers $\rightarrow$ send ProtoOAApplicationAuthReq.
    • applicationAuthResponseCallback (on success) $\rightarrow$ send ProtoOAAccountAuthReq.
    • accountAuthResponseCallback (on success) $\rightarrow$ send data requests (like ProtoOAGetTrendbarsReq).