How to use current price inside an if condition? (OpenApiPy)

Created at 27 Feb 2022, 11:52
How’s your experience with the cTrader Platform?
Your feedback is crucial to cTrader's development. Please take a few seconds to share your opinion and help us improve your trading experience. Thanks!
PR

prenven570

Joined 24.12.2021

How to use current price inside an if condition? (OpenApiPy)
27 Feb 2022, 11:52


Hello.
My goal is to set a buy or sell condition inside a function, 
using the current price updated.

After I send a ProtoOASubscribeSpotsReq I callback the "buy_sell_condition" function,
but when i run all i get this error: builtins.AttributeError: ask 

This is some of my code:

Thanks.

def buy_sell_condition(result):

    while True:
    
        price_message = Protobuf.extract(result)
        current_price = price_message.ask
       
	if current_price >= #some condition:
	     #buy
	      break





def sendProtoOASubscribeSpotsReq(result):
    
    symbolId = 22395
    timeInSeconds = 2
    subscribeToSpotTimestamp = False 
    clientMsgId = None
    
    request = ProtoOASubscribeSpotsReq()
    request.ctidTraderAccountId = currentAccountId
    request.symbolId.append(int(symbolId))
    request.subscribeToSpotTimestamp = subscribeToSpotTimestamp if type(subscribeToSpotTimestamp) is bool else bool(subscribeToSpotTimestamp)
    deferred = client.send(request, clientMsgId = clientMsgId)
    deferred.addErrback(onError)
    deferred.addCallbacks(buy_sell_condition, onError)



def onMessageReceived(client, message): # Callback for receiving all messages

    if message.payloadType in [ProtoOASpotEvent().payloadType, ProtoHeartbeatEvent().payloadType, ProtoOAAccountAuthRes().payloadType, ProtoOAApplicationAuthRes().payloadType, ProtoOASymbolsListRes().payloadType, ProtoOAGetTrendbarsRes().payloadType]:
        return
    print("\nMessage received: \n", Protobuf.extract(message))

 


@prenven570
Replies

amusleh
28 Feb 2022, 09:02

Hi,

The way you coded it is not correct.

I see most of your issues are related to your Python skills not to Open API.

If you want to send a new order request based on a condition that uses current price then you have to use the Spot event for getting the price, once you got the price check the condition if it's ok then send a new order request.

ProtoOASpotEvent has the bid/ask properties, and it's not in actual price, you have to transform is to price by dividing it to 100000.

The OpenApiPy uses Twisted and you have to use callbacks, the execution flow is not sequential.


@amusleh

prenven570
28 Feb 2022, 09:23

RE:

amusleh said:

Hi,

The way you coded it is not correct.

I see most of your issues are related to your Python skills not to Open API.

If you want to send a new order request based on a condition that uses current price then you have to use the Spot event for getting the price, once you got the price check the condition if it's ok then send a new order request.

ProtoOASpotEvent has the bid/ask properties, and it's not in actual price, you have to transform is to price by dividing it to 100000.

The OpenApiPy uses Twisted and you have to use callbacks, the execution flow is not sequential.

Hello, thanks for the answer. But how can I get the updated price in another function?

I get it inside the onMessageReceived function, but when I use global to use price variable in another function, I don't get the updated price.

But I get only one price: 3928229, 3928229, 3928229...

 


@prenven570

amusleh
01 Mar 2022, 09:25 ( Updated at: 01 Mar 2022, 09:26 )

Hi,

There are lots of ways that you can do that, it depends on what design pattern you follow.

A simple solution will be to create a symbol class, get all symbols from API and transform them to your symbol class instances.

The symbol class should have a bid and ask property, store all those Symbols inside a list or dictionary with their name as key.

The symbols collection should be available on your global scope or the on message received method scope.

Then subscribe to spot event for all those symbols, whenever you receive the bid/ask prices of a symbol update the symbol instance bid/ask properties.

This way you will have access always to latest bid/ask prices of all symbols.

As I said on my previous post, it's not something related to Open API or OpenApiPy, it's related to your Python coding skill.


@amusleh

prenven570
01 Mar 2022, 13:59

RE:

amusleh said:

Hi,

There are lots of ways that you can do that, it depends on what design pattern you follow.

A simple solution will be to create a symbol class, get all symbols from API and transform them to your symbol class instances.

The symbol class should have a bid and ask property, store all those Symbols inside a list or dictionary with their name as key.

The symbols collection should be available on your global scope or the on message received method scope.

Then subscribe to spot event for all those symbols, whenever you receive the bid/ask prices of a symbol update the symbol instance bid/ask properties.

This way you will have access always to latest bid/ask prices of all symbols.

As I said on my previous post, it's not something related to Open API or OpenApiPy, it's related to your Python coding skill.

Hello, yes it's probably related to my coding skills. 

It would be nice if there were more concrete examples in the openApiPy repository, in this way people who haven't much experience would be able to code some basic systems. 

I think I'm not asking something that hard, only how to set correctly a price condition, it would be very helpful. Please, think about it. Thanks.

 


@prenven570

amusleh
01 Mar 2022, 14:26

Hi,

You can do it like this:

# this will contain all symbol IDs with their bid/ask prices
symbolsData = dict()

def symbolsResponseCallback(result):
    print("\nSymbols received")
    symbols = Protobuf.extract(result)
    global symbolsData
    for symbol in symbols.symbol:
        symbolsData.append(symbol.symbolId, (0, 0))
        spotRequest = ProtoOASubscribeSpotsReq()
        spotRequest.symbolId = symbol.symbolId
        spotRequest.ctidTraderAccountId = credentials["AccountId"]
        deferred = client.send(request)
        deferred.addErrback(onError)
    
def accountAuthResponseCallback(result):
    print("\nAccount authenticated")
    request = ProtoOASymbolsListReq()
    request.ctidTraderAccountId = credentials["AccountId"]
    request.includeArchivedSymbols = False
    deferred = client.send(request)
    deferred.addCallbacks(symbolsResponseCallback, onError)
    
def applicationAuthResponseCallback(result):
    print("\nApplication authenticated")
    request = ProtoOAAccountAuthReq()
    request.ctidTraderAccountId = credentials["AccountId"]
    request.accessToken = credentials["AccessToken"]
    deferred = client.send(request)
    deferred.addCallbacks(accountAuthResponseCallback, onError)

def onError(client, failure): # Call back for errors
    print("\nMessage Error: ", failure)

def disconnected(client, reason): # Callback for client disconnection
    print("\nDisconnected: ", reason)

def onMessageReceived(client, message): # Callback for receiving all messages
    if message.payloadType in [ProtoHeartbeatEvent().payloadType, ProtoOAAccountAuthRes().payloadType, ProtoOAApplicationAuthRes().payloadType, ProtoOASymbolsListRes().payloadType, ProtoOAGetTrendbarsRes().payloadType]:
        return
    elif message.payloadType == ProtoOASpotEvent().payloadType:
        global symbolsData
        spotEvent = Protobuf.extract(message)
        symbolsData[spotEvent.symbolId] = (spotEvent.bid / 100000, spotEvent.ask / 100000)
        # now you have the symbol prices, do anything you want to here or by using
        # the symbolsData dictionary
    #print("\nMessage received: \n", Protobuf.extract(message))
    
def connected(client): # Callback for client connection
    print("\nConnected")
    request = ProtoOAApplicationAuthReq()
    request.clientId = credentials["ClientId"]
    request.clientSecret = credentials["Secret"]
    deferred = client.send(request)
    deferred.addCallbacks(applicationAuthResponseCallback, onError)
    
# Setting optional client callbacks
client.setConnectedCallback(connected)
client.setDisconnectedCallback(disconnected)
client.setMessageReceivedCallback(onMessageReceived)

My code might have some issues as I haven't tested it but it will give you an idea.


@amusleh

prenven570
01 Mar 2022, 15:31

RE:

amusleh said:

Hi,

You can do it like this:

# this will contain all symbol IDs with their bid/ask prices
symbolsData = dict()

def symbolsResponseCallback(result):
    print("\nSymbols received")
    symbols = Protobuf.extract(result)
    global symbolsData
    for symbol in symbols.symbol:
        symbolsData.append(symbol.symbolId, (0, 0))
        spotRequest = ProtoOASubscribeSpotsReq()
        spotRequest.symbolId = symbol.symbolId
        spotRequest.ctidTraderAccountId = credentials["AccountId"]
        deferred = client.send(request)
        deferred.addErrback(onError)
    
def accountAuthResponseCallback(result):
    print("\nAccount authenticated")
    request = ProtoOASymbolsListReq()
    request.ctidTraderAccountId = credentials["AccountId"]
    request.includeArchivedSymbols = False
    deferred = client.send(request)
    deferred.addCallbacks(symbolsResponseCallback, onError)
    
def applicationAuthResponseCallback(result):
    print("\nApplication authenticated")
    request = ProtoOAAccountAuthReq()
    request.ctidTraderAccountId = credentials["AccountId"]
    request.accessToken = credentials["AccessToken"]
    deferred = client.send(request)
    deferred.addCallbacks(accountAuthResponseCallback, onError)

def onError(client, failure): # Call back for errors
    print("\nMessage Error: ", failure)

def disconnected(client, reason): # Callback for client disconnection
    print("\nDisconnected: ", reason)

def onMessageReceived(client, message): # Callback for receiving all messages
    if message.payloadType in [ProtoHeartbeatEvent().payloadType, ProtoOAAccountAuthRes().payloadType, ProtoOAApplicationAuthRes().payloadType, ProtoOASymbolsListRes().payloadType, ProtoOAGetTrendbarsRes().payloadType]:
        return
    elif message.payloadType == ProtoOASpotEvent().payloadType:
        global symbolsData
        spotEvent = Protobuf.extract(message)
        symbolsData[spotEvent.symbolId] = (spotEvent.bid / 100000, spotEvent.ask / 100000)
        # now you have the symbol prices, do anything you want to here or by using
        # the symbolsData dictionary
    #print("\nMessage received: \n", Protobuf.extract(message))
    
def connected(client): # Callback for client connection
    print("\nConnected")
    request = ProtoOAApplicationAuthReq()
    request.clientId = credentials["ClientId"]
    request.clientSecret = credentials["Secret"]
    deferred = client.send(request)
    deferred.addCallbacks(applicationAuthResponseCallback, onError)
    
# Setting optional client callbacks
client.setConnectedCallback(connected)
client.setDisconnectedCallback(disconnected)
client.setMessageReceivedCallback(onMessageReceived)

My code might have some issues as I haven't tested it but it will give you an idea.

Thank you a lot for the example.

yes, there's an error on line 25: 

AttributeError: 'dict' object has no attribute 'append'

@prenven570

amusleh
02 Mar 2022, 08:27

Hi,

You can change the append call to adding by key: symbolsData[symbol.symbolId] = (0, 0)


@amusleh

crazzy.dev.freelance
06 Feb 2023, 19:42

Implementation of all this stuff is far away from user-friendly and far far away from client-oriented one, too. Hope in the feature it will be reworked and fit into "python-ic" way of doing things.

amusleh said:

Hi,

You can change the append call to adding by key: symbolsData[symbol.symbolId] = (0, 0)

 


@crazzy.dev.freelance

crazzy.dev.freelance
06 Feb 2023, 19:46

Re:

amusleh said:

Hi,

You can change the append call to adding by key: symbolsData[symbol.symbolId] = (0, 0)

Implementation of all this stuff is far away from user-friendly and far far away from client-oriented one, too.

Hope in the feature it will be reworked and fit into "python-ic" way of doing things. 

Will give one straight example - why the hack, creating a MARKET order wont allow to set StopLoss and TakeProfit - while it uses actual symbol entry price and same time you can create LIMIT order using StopLoss and TakeProfit - but this time - you can not use current symbol price without indicating it explicitly?

You need to code some additional modules and callbacks and a lot of stuff just to get the simple stuff to work.


  
 


@crazzy.dev.freelance