Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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()
like image 264
edward Avatar asked Jun 09 '21 15:06

edward


Video Answer


2 Answers

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)

like image 169
bobveringa Avatar answered Oct 26 '22 14:10

bobveringa


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()
like image 27
edward Avatar answered Oct 26 '22 14:10

edward