How to properly close an opened order? (can't pass a ticket number to "position" when sending an order)
Asked Answered
A

3

9

I want to open an order, no problem with that, but if I want to close this order, I need the ticket number, ticket that I can't write manually, it will be given after the order is opened.

From the documentation, I've got this: enter image description here

but I can't pass anything else than 0 to "position": 0 (line 20), otherwise it will not open the order.

Meantime, if position = 0, it will open an order, I'll get a position ticket from result.order, then I have to manually copy it and paste it in the position from the closing order function, like that it will close the order.

So, is there a way of not manually copying the ticket number after each opened order and paste it in the closing function? Or writing an unique ticket in advance for both, open and close, order?

Thank you in advance!

import MetaTrader5 as mt5

if not mt5.initialize():
    print("initialize() failed, error code =",mt5.last_error())
    quit()
    
symbol = "EURUSD"
lot = 0.1
point = mt5.symbol_info(symbol).point
price = mt5.symbol_info_tick(symbol).ask
deviation = 20

def buy():
    request = {
        "action": mt5.TRADE_ACTION_DEAL,
        "symbol": symbol,
        "volume": lot,
        "type": mt5.ORDER_TYPE_BUY,
        "price": price,
        "position": 0, # can't pass anything else than 0 here, otherwise it will not open the order!
        "deviation": deviation,
        "magic": 234000,
        "comment": "python script open",
        "type_time": mt5.ORDER_TIME_GTC,
        "type_filling": mt5.ORDER_FILLING_IOC,
    }
    # send a trading request
    result = mt5.order_send(request)
    
    # check the execution result
    print("2. order_send done, ", result)
    print(result.order)
    
    mt5.shutdown()
    quit()
    


def close():
    close_request={ "action": mt5.TRADE_ACTION_DEAL,
    "symbol": symbol,
    "volume": lot,
    "type": mt5.ORDER_TYPE_SELL,
    "position": 129950610,
    "price": price,
    "deviation": deviation,
    "magic": 0,
    "comment": "python script op",
    "type_time": mt5.ORDER_TIME_GTC,
    "type_filling": mt5.ORDER_FILLING_IOC,
    }
    # send a close request
    result=mt5.order_send(close_request)
    print(result)
    
    
# buy()
# close()
Anticlerical answered 9/6, 2021 at 15:57 Comment(2)
Just to clarify, you want a way to buy and then close a trade request without having to copy the position manually?Faille
Yes, buy, hold it until something is happening and then close that trade, from python, directly without manually copying the ticket numberAnticlerical
A
1

I found a way (hard code it), can be a little bit overwhelming, but it's the only way I can think about it. I'll post the answer; maybe it will be useful for somebody.

So I want functions to buy and sell a specific order; the main issue is the ticket number, so I created functions to buy/open order, to close the order, to get the ticket number (an unique number for the position/order) and magic number (exact number given to EAs) and a function to do what I need (see above), where I compare my magic number with all opened orders. If there is one that will match, it will grab the ticket number and use it to close the order.

import time
import MetaTrader5 as mt5

def init():
    if not mt5.initialize():
        print("initialize() failed, error code =",mt5.last_error())
        quit()


# prepare the buy request structure
lott = 0.15
symboll = "EURUSD"

deviation = 20
magic = 987654321

def buy():
    # establish connection to the MetaTrader 5 terminal
    init()
    
    symbol = symboll
    symbol_info = mt5.symbol_info(symbol)
    
    if symbol_info is None:
        print(symbol, "not found, can not call order_check()")
        mt5.shutdown()
        quit()
    
    # if the symbol is unavailable in MarketWatch, add it
    if not symbol_info.visible:
        print(symbol, "is not visible, trying to switch on")
        if not mt5.symbol_select(symbol,True):
            print("symbol_select({}}) failed, exit",symbol)
            mt5.shutdown()
            quit()

    lot = lott
    point = mt5.symbol_info(symbol).point
    price = mt5.symbol_info_tick(symbol).ask
    
    request = {
        "action": mt5.TRADE_ACTION_DEAL,
        "symbol": symbol,
        "volume": lot,
        "type": mt5.ORDER_TYPE_BUY,
        "price": price,
        "sl": price - 1000 * point,
        "tp": price + 1000 * point,
        "deviation": deviation,
        "magic": magic,
        "comment": "python script open",
        "type_time": mt5.ORDER_TIME_GTC,
        "type_filling": mt5.ORDER_FILLING_IOC,
    }
    
    # send a trading request
    result = mt5.order_send(request)
    # check the execution result
    print("1. order_send(): by {} {} lots at {} with deviation={} points".format(symbol,lot,price,deviation));
    if result.retcode != mt5.TRADE_RETCODE_DONE:
        print("2. order_send failed, retcode={}".format(result.retcode))
        # request the result as a dictionary and display it element by element
        result_dict=result._asdict()
        for field in result_dict.keys():
            print("   {}={}".format(field,result_dict[field]))
            # if this is a trading request structure, display it element by element as well
            if field=="request":
                traderequest_dict=result_dict[field]._asdict()
                for tradereq_filed in traderequest_dict:
                    print("       traderequest: {}={}".format(tradereq_filed,traderequest_dict[tradereq_filed]))
        print("shutdown() and quit")
        mt5.shutdown()
        quit()
 
    print("2. order_send done, ", result)
    print("   opened position with POSITION_TICKET={}".format(result.order))
    print("   sleep 2 seconds before closing position #{}".format(result.order))


def close(ticket_no):
    init()
    symbol = symboll
    symbol_info = mt5.symbol_info(symbol)
    lot = lott
    # create a close request
    position_id=ticket_no
    price=mt5.symbol_info_tick(symbol).bid
    deviation=20
    request={
        "action": mt5.TRADE_ACTION_DEAL,
        "symbol": symbol,
        "volume": lot,
        "type": mt5.ORDER_TYPE_SELL,
        "position": position_id,
        "price": price,
        "deviation": deviation,
        "magic": magic,
        "comment": "python script close",
        "type_time": mt5.ORDER_TIME_GTC,
        "type_filling": mt5.ORDER_FILLING_IOC,
    }
    # send a trading request
    result=mt5.order_send(request)
    # check the execution result
    print("3. close position #{}: sell {} {} lots at {} with deviation={} points".format(position_id,symbol,lot,price,deviation));
    if result.retcode != mt5.TRADE_RETCODE_DONE:
        print("4. order_send failed, retcode={}".format(result.retcode))
        print("   result",result)
    else:
        print("4. position #{} closed, {}".format(position_id,result))
        # request the result as a dictionary and display it element by element
        result_dict=result._asdict()
        for field in result_dict.keys():
            print("   {}={}".format(field,result_dict[field]))
            # if this is a trading request structure, display it element by element as well
            if field=="request":
                traderequest_dict=result_dict[field]._asdict()
                for tradereq_filed in traderequest_dict:
                    print("       traderequest: {}={}".format(tradereq_filed,traderequest_dict[tradereq_filed]))
    
    # shut down connection to the MetaTrader 5 terminal
    mt5.shutdown()
    quit()


def get_ticket_no():
    init()
    symbol = symboll
    symbol_info = mt5.symbol_info(symbol)
    
    positions=mt5.positions_get(symbol=symbol)
    if positions==None:
        print("No positions on EURUSD, error code={}".format(mt5.last_error()))
    elif len(positions)>0:
        print("Total positions on EURUSD =",len(positions))
        # display all open positions
        for position in positions:
            print(position)

    # get the list of positions on symbols whose names contain "*EUR*"
    symmbol_positions=mt5.positions_get()
    if symmbol_positions==None:
        print("No positions with group=\"*EUR*\", error code={}".format(mt5.last_error()))    
    elif len(symmbol_positions)>0:
        lst = list(symmbol_positions)
        ticket_no = lst[0][0] # get the ticket number
        magic_no = lst[0][6] # get the magic number
        print(f'{ticket_no=}')
        print(f'{magic_no=}')
        return ticket_no

    # shut down connection to the MetaTrader 5 terminal
    mt5.shutdown()
    quit()


def get_magic_no():
    init()
    symbol = symboll
    symbol_info = mt5.symbol_info(symbol)
    
    positions=mt5.positions_get(symbol=symbol)
    if positions==None:
        print("No positions on EURUSD, error code={}".format(mt5.last_error()))
    elif len(positions)>0:
        print("Total positions on EURUSD =",len(positions))
        # display all open positions
        for position in positions:
            print(position)

    # get the list of positions on symbols whose names contain "*EUR*"
    symmbol_positions=mt5.positions_get()
    if symmbol_positions==None:
        print("No positions with group=\"*EUR*\", error code={}".format(mt5.last_error()))    
    elif len(symmbol_positions)>0:
        lst = list(symmbol_positions)
        ticket_no = lst[0][0] # get the ticket number
        magic_no = lst[0][6] # get the magic number
        print(f'{ticket_no=}')
        print(f'{magic_no=}')
        return magic_no

    # shut down connection to the MetaTrader 5 terminal
    mt5.shutdown()
    quit()
    

def close_order():
    if get_magic_no() == magic:
        close(get_ticket_no())
    else:
        print("Order not found!")
    
    
buy()
time.sleep(2)
close_order()
Anticlerical answered 16/6, 2021 at 6:37 Comment(0)
F
3

Your question has two parts that I will each address.

Why can't I pass a position value
You mention in your post that you cannot enter anything else than "position": 0 in your initial request. As you already found yourself, the API documentation states

Position ticket. Fill it when changing and closing a position for its clear identification. Usually, it is the same as the ticket of the order that opened the position.

This means that if you already have a ticket and need to modify it, you need to enter a value. The API documentation actually does this in the provided example.

I will include a few snippets here, but I recommend you check out the example provided on the order_send documentation page.

request = {
    "action": mt5.TRADE_ACTION_DEAL,
    "symbol": symbol,
    "volume": lot,
    "type": mt5.ORDER_TYPE_BUY,
    "price": price,
    "sl": price - 100 * point,
    "tp": price + 100 * point,
    "deviation": deviation,
    "magic": 234000,
    "comment": "python script open",
    "type_time": mt5.ORDER_TIME_GTC,
    "type_filling": mt5.ORDER_FILLING_RETURN,
}

As you can see here, the position field is not filled in. This is because it is the first request, and there is nothing to modify, as there is no trade request yet.

The request dict for closing looks like this

position_id = result.order

request={
    "action": mt5.TRADE_ACTION_DEAL,
    "symbol": symbol,
    "volume": lot,
    "type": mt5.ORDER_TYPE_SELL,
    "position": position_id,
    "price": price,
    "deviation": deviation,
    "magic": 234000,
    "comment": "python script close",
    "type_time": mt5.ORDER_TIME_GTC,
    "type_filling": mt5.ORDER_FILLING_RETURN,
}

In the request, you can see two things. The first one is that the position field is filled in, as we are now making a modification to the original request. The second thing that you can see here is that the position_id is taken from the response of the initial request. The position_id is the order field of the response. The documentation for this structure is available here.

How can you adjust your code to close it without manually copying the order number?
Based on your comment, I think this is what you are looking for.

For example, the order_send function already shows how this needs to be done.

The most important thing that you need to do is pass the position_id from the response of the buy() function to the close() function.

What is also noticed is that in your original code, the magic field was set to 234000 for the buy request and to 0 for the close request. When reading the documentation, it didn't explicitly mention that this needs to be the same. However, since it is the same in the example they provide, I also changed it to be the same in the code below.

import MetaTrader5 as mt5

if not mt5.initialize():
    print("initialize() failed, error code =", mt5.last_error())
    quit()

symbol = "EURUSD"
lot = 0.1
point = mt5.symbol_info(symbol).point
price = mt5.symbol_info_tick(symbol).ask
deviation = 20


def buy():
    request = {
        "action": mt5.TRADE_ACTION_DEAL,
        "magic": 234000,
        "symbol": symbol,
        "volume": lot,
        "type": mt5.ORDER_TYPE_BUY,
        "price": price,
        "deviation": deviation,
        "comment": "python script open",
        "type_time": mt5.ORDER_TIME_GTC,
        "type_filling": mt5.ORDER_FILLING_IOC,
    }
    # send a trading request
    result = mt5.order_send(request)

    # check the execution result
    print("2. order_send done, ", result)
    position_id = result.order
    print(position_id)

    mt5.shutdown()
    return position_id


def close(position_id):
    close_request = {"action": mt5.TRADE_ACTION_DEAL,
                     "symbol": symbol,
                     "volume": lot,
                     "type": mt5.ORDER_TYPE_SELL,
                     "position": position_id,
                     "price": price,
                     "deviation": deviation,
                     "magic": 234000,
                     "comment": "python script op",
                     "type_time": mt5.ORDER_TIME_GTC,
                     "type_filling": mt5.ORDER_FILLING_IOC,
                     }
    # send a close request
    result = mt5.order_send(close_request)
    print(result)


pos_id = buy()
close(pos_id)

Faille answered 11/6, 2021 at 23:34 Comment(4)
Thank you for your time! In your example, pos_id = buy() will open an order and close(pos_id) result is None. Apparently can't be grabbed only the position_id buy() and use it another time, or at least, I can't figure it out. how to do it without opening another order.Anticlerical
Have you tried running the example provided on the send_order documentation page?Faille
Yes, I used that example for my testing, but as it is it will open an order then close it after time.sleep(2), as I said, it's weird the ticket number can't be get from an open order function and use it in another function, probably I'm missing something. Thanks for you time!Anticlerical
I was thinking about a solution (for sure there is a better way than hard code it, but at least this one should work): 1. open an order, 2. check the request dict and get the magic with position_get built in function, 3. if the magic will match with my number, get the ticket number (position id) from that dict, 4. use that position id to close that specific order. I see no reason for not working like that (I can't test this approach right now), also I can cast both, buy and close, into separate functions and use them anytime I needAnticlerical
A
1

I found a way (hard code it), can be a little bit overwhelming, but it's the only way I can think about it. I'll post the answer; maybe it will be useful for somebody.

So I want functions to buy and sell a specific order; the main issue is the ticket number, so I created functions to buy/open order, to close the order, to get the ticket number (an unique number for the position/order) and magic number (exact number given to EAs) and a function to do what I need (see above), where I compare my magic number with all opened orders. If there is one that will match, it will grab the ticket number and use it to close the order.

import time
import MetaTrader5 as mt5

def init():
    if not mt5.initialize():
        print("initialize() failed, error code =",mt5.last_error())
        quit()


# prepare the buy request structure
lott = 0.15
symboll = "EURUSD"

deviation = 20
magic = 987654321

def buy():
    # establish connection to the MetaTrader 5 terminal
    init()
    
    symbol = symboll
    symbol_info = mt5.symbol_info(symbol)
    
    if symbol_info is None:
        print(symbol, "not found, can not call order_check()")
        mt5.shutdown()
        quit()
    
    # if the symbol is unavailable in MarketWatch, add it
    if not symbol_info.visible:
        print(symbol, "is not visible, trying to switch on")
        if not mt5.symbol_select(symbol,True):
            print("symbol_select({}}) failed, exit",symbol)
            mt5.shutdown()
            quit()

    lot = lott
    point = mt5.symbol_info(symbol).point
    price = mt5.symbol_info_tick(symbol).ask
    
    request = {
        "action": mt5.TRADE_ACTION_DEAL,
        "symbol": symbol,
        "volume": lot,
        "type": mt5.ORDER_TYPE_BUY,
        "price": price,
        "sl": price - 1000 * point,
        "tp": price + 1000 * point,
        "deviation": deviation,
        "magic": magic,
        "comment": "python script open",
        "type_time": mt5.ORDER_TIME_GTC,
        "type_filling": mt5.ORDER_FILLING_IOC,
    }
    
    # send a trading request
    result = mt5.order_send(request)
    # check the execution result
    print("1. order_send(): by {} {} lots at {} with deviation={} points".format(symbol,lot,price,deviation));
    if result.retcode != mt5.TRADE_RETCODE_DONE:
        print("2. order_send failed, retcode={}".format(result.retcode))
        # request the result as a dictionary and display it element by element
        result_dict=result._asdict()
        for field in result_dict.keys():
            print("   {}={}".format(field,result_dict[field]))
            # if this is a trading request structure, display it element by element as well
            if field=="request":
                traderequest_dict=result_dict[field]._asdict()
                for tradereq_filed in traderequest_dict:
                    print("       traderequest: {}={}".format(tradereq_filed,traderequest_dict[tradereq_filed]))
        print("shutdown() and quit")
        mt5.shutdown()
        quit()
 
    print("2. order_send done, ", result)
    print("   opened position with POSITION_TICKET={}".format(result.order))
    print("   sleep 2 seconds before closing position #{}".format(result.order))


def close(ticket_no):
    init()
    symbol = symboll
    symbol_info = mt5.symbol_info(symbol)
    lot = lott
    # create a close request
    position_id=ticket_no
    price=mt5.symbol_info_tick(symbol).bid
    deviation=20
    request={
        "action": mt5.TRADE_ACTION_DEAL,
        "symbol": symbol,
        "volume": lot,
        "type": mt5.ORDER_TYPE_SELL,
        "position": position_id,
        "price": price,
        "deviation": deviation,
        "magic": magic,
        "comment": "python script close",
        "type_time": mt5.ORDER_TIME_GTC,
        "type_filling": mt5.ORDER_FILLING_IOC,
    }
    # send a trading request
    result=mt5.order_send(request)
    # check the execution result
    print("3. close position #{}: sell {} {} lots at {} with deviation={} points".format(position_id,symbol,lot,price,deviation));
    if result.retcode != mt5.TRADE_RETCODE_DONE:
        print("4. order_send failed, retcode={}".format(result.retcode))
        print("   result",result)
    else:
        print("4. position #{} closed, {}".format(position_id,result))
        # request the result as a dictionary and display it element by element
        result_dict=result._asdict()
        for field in result_dict.keys():
            print("   {}={}".format(field,result_dict[field]))
            # if this is a trading request structure, display it element by element as well
            if field=="request":
                traderequest_dict=result_dict[field]._asdict()
                for tradereq_filed in traderequest_dict:
                    print("       traderequest: {}={}".format(tradereq_filed,traderequest_dict[tradereq_filed]))
    
    # shut down connection to the MetaTrader 5 terminal
    mt5.shutdown()
    quit()


def get_ticket_no():
    init()
    symbol = symboll
    symbol_info = mt5.symbol_info(symbol)
    
    positions=mt5.positions_get(symbol=symbol)
    if positions==None:
        print("No positions on EURUSD, error code={}".format(mt5.last_error()))
    elif len(positions)>0:
        print("Total positions on EURUSD =",len(positions))
        # display all open positions
        for position in positions:
            print(position)

    # get the list of positions on symbols whose names contain "*EUR*"
    symmbol_positions=mt5.positions_get()
    if symmbol_positions==None:
        print("No positions with group=\"*EUR*\", error code={}".format(mt5.last_error()))    
    elif len(symmbol_positions)>0:
        lst = list(symmbol_positions)
        ticket_no = lst[0][0] # get the ticket number
        magic_no = lst[0][6] # get the magic number
        print(f'{ticket_no=}')
        print(f'{magic_no=}')
        return ticket_no

    # shut down connection to the MetaTrader 5 terminal
    mt5.shutdown()
    quit()


def get_magic_no():
    init()
    symbol = symboll
    symbol_info = mt5.symbol_info(symbol)
    
    positions=mt5.positions_get(symbol=symbol)
    if positions==None:
        print("No positions on EURUSD, error code={}".format(mt5.last_error()))
    elif len(positions)>0:
        print("Total positions on EURUSD =",len(positions))
        # display all open positions
        for position in positions:
            print(position)

    # get the list of positions on symbols whose names contain "*EUR*"
    symmbol_positions=mt5.positions_get()
    if symmbol_positions==None:
        print("No positions with group=\"*EUR*\", error code={}".format(mt5.last_error()))    
    elif len(symmbol_positions)>0:
        lst = list(symmbol_positions)
        ticket_no = lst[0][0] # get the ticket number
        magic_no = lst[0][6] # get the magic number
        print(f'{ticket_no=}')
        print(f'{magic_no=}')
        return magic_no

    # shut down connection to the MetaTrader 5 terminal
    mt5.shutdown()
    quit()
    

def close_order():
    if get_magic_no() == magic:
        close(get_ticket_no())
    else:
        print("Order not found!")
    
    
buy()
time.sleep(2)
close_order()
Anticlerical answered 16/6, 2021 at 6:37 Comment(0)
B
1

maybe late

request={
    "action": mt5.TRADE_ACTION_REMOVE,
    "order": ticket
    }
result = mt5.order_send(request)
Bullhorn answered 27/11, 2023 at 21:3 Comment(1)
Remember that Stack Overflow isn't just intended to solve the immediate problem, but also to help future readers find solutions to similar problems, which requires understanding the underlying code. This is especially important for members of our community who are beginners, and not familiar with the syntax. Given that, can you edit your answer to include an explanation of what you're doing and why you believe it is the best approach?Bethesde

© 2022 - 2024 — McMap. All rights reserved.