Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

There seems to be an issue with executing orders after they have been successfully executed twice before. #25

Open
amircp opened this issue Jul 29, 2023 · 6 comments

Comments

@amircp
Copy link

amircp commented Jul 29, 2023

Hi,
After executing two consecutive trades using BUY and SELL Market types the next ones cannot be executed the log says it were executed but they aren't.

For example
i open a Buy order and then i try to close it using the method close_all() everything works fine. (I use this method because the close position by id doesn't work at all).

After that first successful execution if i try to open another one (in the same session) the new buy order executes correctly but if i try to use again the close_all method the buy order still persists in the market.

Another scenery is:
I can open many buy market orders but i cannot close them (using the close all method).

my implementations:

Buy ORDER

  if not self.api.isconnected():
            raise CTraderDisconnected("CTrader is not connected")
        try:
            logger.info(f"🕦 Buying ${order.quantity} from {order.symbol}")

            price = self.api.quote()
            logger.info(f"Quote: {price=}")
            price = price[order.symbol]["bid"]

            symbol = order.symbol
            volume = order.quantity
            stop_loss = 0
            take_profit = 0

            oid = self.api.buy(symbol=symbol, volume=volume, stoploss=stop_loss, takeprofit=take_profit)
            logger.info(f"CTrader Position {oid}")

Close all:

  positions = self.api.positions()
            if len(positions) < 1:
                break

            logger.info(positions)
            self.api.close_all()
            time.sleep(5)

Sometimes, the second try produces an unexpected infinite loop with a number of 16 digits.

I have some thoughts on what might be going on, but I need to test and debug those ideas when the market opens with a demo account.

Cheers

@traderpedroso
Copy link
Member

First and foremost, my friend, I appreciate your input on the subject of consecutive order placements. I've run into some trouble with Jupyter Notebook and the fix api, however, I plan to run some tests based on your insights. Please know that any PRs are highly encouraged. I apologize for my late response, I've been heavily involved in an AI project aimed at the financial market recently. I intend to perform the tests this week and aim to resolve some bugs. I've observed an issue with the FIX API concerning pauses between successive executions - this hasn't always been the case. I've also noted disparities across different brokers, particularly between demo and real accounts.

Hi, After executing two consecutive trades using BUY and SELL Market types the next ones cannot be executed the log says it were executed but they aren't.

For example i open a Buy order and then i try to close it using the method close_all() everything works fine. (I use this method because the close position by id doesn't work at all).

After that first successful execution if i try to open another one (in the same session) the new buy order executes correctly but if i try to use again the close_all method the buy order still persists in the market.

Another scenery is: I can open many buy market orders but i cannot close them (using the close all method).

my implementations:

Buy ORDER

  if not self.api.isconnected():
            raise CTraderDisconnected("CTrader is not connected")
        try:
            logger.info(f"🕦 Buying ${order.quantity} from {order.symbol}")

            price = self.api.quote()
            logger.info(f"Quote: {price=}")
            price = price[order.symbol]["bid"]

            symbol = order.symbol
            volume = order.quantity
            stop_loss = 0
            take_profit = 0

            oid = self.api.buy(symbol=symbol, volume=volume, stoploss=stop_loss, takeprofit=take_profit)
            logger.info(f"CTrader Position {oid}")

Close all:

  positions = self.api.positions()
            if len(positions) < 1:
                break

            logger.info(positions)
            self.api.close_all()
            time.sleep(5)

Sometimes, the second try produces an unexpected infinite loop with a number of 16 digits.

I have some thoughts on what might be going on, but I need to test and debug those ideas when the market opens with a demo account.

Cheers

First and foremost, my friend, I appreciate your input on the subject of consecutive order placements. I've run into some trouble with Jupyter Notebook and the fix api, however, I plan to run some tests based on your insights. Please know that any PRs are highly encouraged. I apologize for my late response, I've been heavily involved in an AI project aimed at the financial market recently. I intend to perform the tests this week and aim to resolve some bugs. I've observed an issue with the FIX API concerning pauses between successive executions - this hasn't always been the case. I've also noted disparities across different brokers, particularly between demo and real accounts.

@amircp
Copy link
Author

amircp commented Aug 2, 2023

First and foremost, my friend, I appreciate your input on the subject of consecutive order placements. I've run into some trouble with Jupyter Notebook and the fix api, however, I plan to run some tests based on your insights. Please know that any PRs are highly encouraged. I apologize for my late response, I've been heavily involved in an AI project aimed at the financial market recently. I intend to perform the tests this week and aim to resolve some bugs. I've observed an issue with the FIX API concerning pauses between successive executions - this hasn't always been the case. I've also noted disparities across different brokers, particularly between demo and real accounts.

Hi,
I'm working on my spare time, and currently, I haven't had any success in trying to fix the problems. I am currently trying to understand how the positions are handled in the position list attribute, and it's good to know that PRs are welcome. Once I fix the positions problem, I'll be creating one.

I'd also like to mention that I have noticed the differences related to demo and real accounts.

btw, Congratulations on your AI project, and I wish you the best!

@amircp
Copy link
Author

amircp commented Aug 4, 2023

I have found the problem.

When tag 35="AP" is received from the Broker, the parse_trade_message method searches in the binary data for the end of the FIX message, which in all cases is the checksum tag (tag 10)

match = re.search(rb"10=\d{3}\x01", self.tstream.peek(self.tstream.count()))

However, the FIX message received contains various messages grouped into just one response, as shown in the following example:

b'8=FIX.4.4\x019=162\x0135=AP\x0134=2\x0149=CSERVER\x0150=TRADE\x0152=20230804-19:55:06.286\x0156=demo.icmarkets.0000000\x0157=TRADE\x0155=10014\x01710=1\x01721=349730793\x01727=2\x01728=0\x01730=15347.9\x01702=1\x01704=1\x01705=0\x0110=218\x018=FIX.4.4\x019=162\x0135=AP\x0134=3\x0149=CSERVER\x0150=TRADE\x0152=20230804-19:55:06.286\x0156=demo.icmarkets.0000000\x0157=TRADE\x0155=10014\x01710=1\x01721=349731225\x01727=2\x01728=0\x01730=15349.8\x01702=1\x01704=1\x01705=0\x0110=211\x018=FIX.4.4\x019=137\x0135=j\x0134=4\x0149=CSERVER\x0150=TRADE\x0152=20230804-19:55:06.286\x0156=demo.icmarkets.0000000\x0157=TRADE\x0158=ORDER_NOT_FOUND:no orders found\x01379=1\x01380=0\x0110=078\x01'

If we carefully look into the received response, we can split it into 3 FIX messages:

b'8=FIX.4.4\x019=162\x0135=AP\x0134=2\x0149=CSERVER\x0150=TRADE\x0152=20230804-19:55:06.286\x0156=demo.icmarkets.0000000\x0157=TRADE\x0155=10014\x01710=1\x01721=349730793\x01727=2\x01728=0\x01730=15347.9\x01702=1\x01704=1\x01705=0\x0110=218

8=FIX.4.4\x019=162\x0135=AP\x0134=3\x0149=CSERVER\x0150=TRADE\x0152=20230804-19:55:06.286\x0156=demo.icmarkets.0000000\x0157=TRADE\x0155=10014\x01710=1\x01721=349731225\x01727=2\x01728=0\x01730=15349.8\x01702=1\x01704=1\x01705=0\x0110=211

18=FIX.4.4\x019=137\x0135=j\x0134=4\x0149=CSERVER\x0150=TRADE\x0152=20230804-19:55:06.286\x0156=demo.icmarkets.0000000\x0157=TRADE\x0158=ORDER_NOT_FOUND:no orders found\x01379=1\x01380=0\x0110=078\x01'

Unfortunately, the regex is matching just the first one, resulting in parsing only the first message and causing the position list to contain only ONE position. This is why we can't close the other orders. Furthermore, related to this problem, the position list callback prevents the right execution and filling of the position list. (This is why subsequent orders cannot be closed after closing the first one).

I have completed half of the fix, but I think I will need to refactor the callback for positions.

@traderpedroso
Copy link
Member

I have found the problem.

When tag 35="AP" is received from the Broker, the parse_trade_message method searches in the binary data for the end of the FIX message, which in all cases is the checksum tag (tag 10)

match = re.search(rb"10=\d{3}\x01", self.tstream.peek(self.tstream.count()))

However, the FIX message received contains various messages grouped into just one response, as shown in the following example:

b'8=FIX.4.4\x019=162\x0135=AP\x0134=2\x0149=CSERVER\x0150=TRADE\x0152=20230804-19:55:06.286\x0156=demo.icmarkets.0000000\x0157=TRADE\x0155=10014\x01710=1\x01721=349730793\x01727=2\x01728=0\x01730=15347.9\x01702=1\x01704=1\x01705=0\x0110=218\x018=FIX.4.4\x019=162\x0135=AP\x0134=3\x0149=CSERVER\x0150=TRADE\x0152=20230804-19:55:06.286\x0156=demo.icmarkets.0000000\x0157=TRADE\x0155=10014\x01710=1\x01721=349731225\x01727=2\x01728=0\x01730=15349.8\x01702=1\x01704=1\x01705=0\x0110=211\x018=FIX.4.4\x019=137\x0135=j\x0134=4\x0149=CSERVER\x0150=TRADE\x0152=20230804-19:55:06.286\x0156=demo.icmarkets.0000000\x0157=TRADE\x0158=ORDER_NOT_FOUND:no orders found\x01379=1\x01380=0\x0110=078\x01'

If we carefully look into the received response, we can split it into 3 FIX messages:

b'8=FIX.4.4\x019=162\x0135=AP\x0134=2\x0149=CSERVER\x0150=TRADE\x0152=20230804-19:55:06.286\x0156=demo.icmarkets.0000000\x0157=TRADE\x0155=10014\x01710=1\x01721=349730793\x01727=2\x01728=0\x01730=15347.9\x01702=1\x01704=1\x01705=0\x0110=218

8=FIX.4.4\x019=162\x0135=AP\x0134=3\x0149=CSERVER\x0150=TRADE\x0152=20230804-19:55:06.286\x0156=demo.icmarkets.0000000\x0157=TRADE\x0155=10014\x01710=1\x01721=349731225\x01727=2\x01728=0\x01730=15349.8\x01702=1\x01704=1\x01705=0\x0110=211

18=FIX.4.4\x019=137\x0135=j\x0134=4\x0149=CSERVER\x0150=TRADE\x0152=20230804-19:55:06.286\x0156=demo.icmarkets.0000000\x0157=TRADE\x0158=ORDER_NOT_FOUND:no orders found\x01379=1\x01380=0\x0110=078\x01'

Unfortunately, the regex is matching just the first one, resulting in parsing only the first message and causing the position list to contain only ONE position. This is why we can't close the other orders. Furthermore, related to this problem, the position list callback prevents the right execution and filling of the position list. (This is why subsequent orders cannot be closed after closing the first one).

I have completed half of the fix, but I think I will need to refactor the callback for positions.
Good evening, my friend. I apologize for the delay in responding. Lately, I've been extremely busy and haven't had the time to check. I'm hopeful that next week will be less hectic, and I'll definitely review this matter. I'll revisit the document to see if there have been any updates or if it's an initial project bug. Thank you for your cooperation. I intend to return promptly to focus on the projects at EJTrader.

@Greg-Mukuria
Copy link

Nice, work. How about an implementation of the same in rust, for latency's sake?

@traderpedroso
Copy link
Member

Nice, work. How about an implementation of the same in rust, for latency's sake?

I conducted some tests in Rust and observed no significant change in speed compared to Python. I believe Python is adequately serving our needs in this context.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants