mt5.order_send() returns None

 

Thank you in advance for helping me!


I'm coding automatic trading system in python.

I'd like to get positions and close them automatically.

However, mt5.order_send() returns None(not any errors but 'None'!) if request['position'] is input from pd.Series data.

When I directly input position id code, the function works.


the code is below:

*mt5_initialize() is user function that calls mt5.initialize()

*tickets[i] is the position id (int32).


def close_positions(tickets, symbol, lot):
    symbol = tickets.name
    for i in range(len(tickets)):
        mt5_initialize()
        price = mt5.symbol_info_tick(symbol).bid
        deviation = 20
        position_id = tickets[i]
        request = {
            'action': mt5.TRADE_ACTION_DEAL,
            'symbol': symbol,
            'volume': lot,
            'type': mt5.ORDER_TYPE_SELL,
            'position': position_id,
            'price': price,
            'deviation': deviation,
            'comment': 'python script close',
            'type_time': mt5.ORDER_TIME_GTC,
            'type_filling': mt5.ORDER_FILLING_FOK,
        }
        request['position'] = tickets[i]
        result = mt5.order_send(request)
        print(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, because:', error_desc[result.retcode])
            print('   result', result)
        else:
            print('4. position #{} closed, {}'.format(position_id, result))
    mt5.shutdown()
    print('close positions of', symbol)
    return None
Documentation on MQL5: Constants, Enumerations and Structures / Trade Constants / Trade Operation Types
Documentation on MQL5: Constants, Enumerations and Structures / Trade Constants / Trade Operation Types
  • www.mql5.com
Trading is done by sending orders to open positions using the OrderSend() function, as well as to place, modify or delete pending orders. Each trade order refers to the type of the requested operation. Trading operations are described in the ENUM_TRADE_REQUEST_ACTIONS enumeration...
 
是磑 佐藤:

However, mt5.order_send() returns None(not any errors but 'None'!) if request['position'] is input from pd.Series data.

When I directly input position id code, the function works.

This function is fine (apart from the redundant but harmless "request['position'] = tickets[i]").

Are you able to show the lines that calls close_positions()? Include parts that fill up "tickets"...

 
Seng Joo Thio:

This function is fine (apart from the redundant but harmless "request['position'] = tickets[i]").

Are you able to show the lines that calls close_positions()? Include parts that fill up "tickets"...

Hi Seng, thank you for cooperation!

This is the logic that get tickets:

# get tickets of open positions
def get_tickets(symbol):
    mt5_initialize()
    positions = mt5.positions_get(symbol=symbol)
    tickets = pd.DataFrame(index=range(len(positions)), columns=['ticket', 'volume'])
    for i in range(len(positions)):
        tickets.loc[i, 'ticket'] = positions[i].ticket
        tickets.loc[i, 'volume'] = positions[i].volume
    mt5.shutdown()
    tickets['ticket'] = tickets['ticket'].astype('int')
    tickets['volume'] = tickets['volume'].astype('float')
    tickets['symbol'] = symbol
    return tickets


# get single open position
def get_position(symbol):
    mt5_initialize()
    positions = mt5.positions_get(symbol=symbol)
    mt5.shutdown()
    net_position = 0
    net_profit = 0
    if len(positions) >= 1:
        for i in range(len(positions)):
            if positions[i].type == 0:
                sign = 1
            elif positions[i].type == 1:
                sign = -1
            net_position += positions[i].volume * sign
            net_profit += (positions[i].price_current - positions[i].price_open) * positions[i].volume * sign
        net_amount = net_position * positions[0].price_current
    else:
        net_amount = 0
        net_profit = 0
    return net_amount, net_profit

Using these functions, I execute this way:

tickets = get_tickets('BTCJPY')

close_positions(tickets)

 

Pandas is good for working with large sets of data, but it's inefficient to setup and tear down. It's also unnecessary since mt5 is returning pure python objects, so it's better to work with pure python for what you're doing. In addition, you should only setup and tear-down the mt5 module only once in your program. Doing it inside of each loop iteration is absolutely going to kill your script performance. Here's an example:


import MetaTrader5 as mt5


def raw_order(**kwargs):
    return mt5.order_send(kwargs)


def main():
    for pos in mt5.positions_get():
        info = mt5.symbol_info_tick(pos.symbol)
        is_long = pos.type == mt5.POSITION_TYPE_BUY
        order_type, price = (mt5.ORDER_TYPE_SELL, info.bid) if is_long else (mt5.ORDER_TYPE_BUY, info.ask)
        result = raw_order(
            action=mt5.TRADE_ACTION_DEAL,
            type=order_type,
            symbol=pos.symbol,
            volume=pos.volume,
            position=pos.ticket,
            price=price,
            comment="close all",
        )
        print(result)

    for ord in mt5.orders_get():
        result = raw_order(order=ord.ticket, action=mt5.TRADE_ACTION_REMOVE)
        print(result)


if __name__ == "__main__":
    if mt5.initialize():
        main()
    mt5.shutdown()
 
nicholi shen:

Pandas is good for working with large sets of data, but it's inefficient to setup and tear down. It's also unnecessary since mt5 is returning pure python objects, so it's better to work with pure python for what you're doing. In addition, you should only setup and tear-down the mt5 module only once in your program. Doing it inside of each loop iteration is absolutely going to kill your script performance. Here's an example:


Hi nicholi,

Thank you for the sample code.

I'd like to close existing open positions (= netting), but the method that you showed seems to order opposite new positions (=hedging).

Is there any way to close positions via python API?

 
是磑 佐藤:

Hi nicholi,

Thank you for the sample code.

I'd like to close existing open positions (= netting), but the method that you showed seems to order opposite new positions (=hedging).

Is there any way to close positions via python API?

That's how you close either with MT5. In fact, there is even a Close function included in the MetaTrader5 module so your code could be greatly reduced and refactored to something like this. 

def open_position_symbols():
    return tuple(set(p.symbol for p in mt5.positions_get()))

def net_position(symbol):
    return sum(
        p.volume if p.type==mt5.POSITION_TYPE_BUY else -p.volume
        for p in mt5.positions_get(symbol=symbol)
    )

def net_profit(symbol):
    return sum(p.profit for p in mt5.positions_get(symbol=symbol))

def verbose_status(symbol):
    return '{} - Net position = {}, Net profit = {}'.format(
        symbol,
        net_position(symbol),
        net_profit(symbol)
    )

def close_all():
    for symbol in open_position_symbols():
        print(f'Closing: {verbose_status(symbol)}')
        mt5.Close(symbol=symbol)

if __name__ == "__main__":
    try:
        if mt5.initialize():
            close_all()
    finally:
        mt5.shutdown()
 
nicholi shen:

That's how you close either with MT5. In fact, there is even a Close function included in the MetaTrader5 module so your code could be greatly reduced and refactored to something like this. 

Thank you very much!!

I didn't know mt5.Close() function.

Have a nice weekend!

 
是磑 佐藤:

Thank you very much!!

I didn't know mt5.Close() function.

Have a nice weekend!

Dear nicholi,

After your final reply, I use your close_all() function some times.

First some times the function works well, but it gets not to work sometimes.

Do you know the reason why?

 

No idea why but you really shouldn't be closing orders that way on a hedging account anyway. You would first want to flatten the position the reconcile the orders as closed using the closeby feature. 


import MetaTrader5 as mt5


def raw_order(**kwargs):
    return mt5.order_send(kwargs)


def open_position_symbols():
    symbols = list(set(p.symbol for p in mt5.positions_get()))
    symbols = sorted(symbols, key=lambda s: abs(net_position(mt5.positions_get(symbol=s))), reverse=True)
    return symbols


def net_position(positions):
    return sum(p.volume if p.type == mt5.POSITION_TYPE_BUY else -p.volume for p in positions)


def flatten(symbol):
    positions = mt5.positions_get(symbol=symbol)
    net_pos = net_position(positions)
    if net_pos == 0:
        return mt5.TRADE_RETCODE_DONE
    info = mt5.symbol_info_tick(symbol)
    order_type, price, comment = (
        (mt5.ORDER_TYPE_SELL, info.bid, "flatten long"),
        (mt5.ORDER_TYPE_BUY, info.ask, "flatten short")
    )[net_pos < 0]
    result = raw_order(
        action=mt5.TRADE_ACTION_DEAL,
        type=order_type,
        symbol=symbol,
        volume=abs(net_pos),
        price=price,
        comment=comment,
    )
    return result.retcode


def reconcile(symbol):
    positions = mt5.positions_get(symbol=symbol)
    if not positions:
        return mt5.TRADE_RETCODE_DONE
    try:
        long = next(p for p in positions if p.type == mt5.POSITION_TYPE_BUY)
        short = next(p for p in positions if p.type == mt5.POSITION_TYPE_SELL)
    except StopIteration:
        return mt5.TRADE_RETCODE_ERROR
    result = raw_order(
        action=mt5.TRADE_ACTION_CLOSE_BY,
        position=long.ticket,
        position_by=short.ticket,
    )
    if result.retcode == mt5.TRADE_RETCODE_DONE:
        return reconcile(symbol)
    return mt5.TRADE_RETCODE_ERROR


def close_all():
    symbols = open_position_symbols()
    for symbol in symbols:
        if (res := flatten(symbol)) != mt5.TRADE_RETCODE_DONE:
            print(f"CloseAllError: did not flatten {symbol}, error code={res}")
    for symbol in symbols:
        if (res := reconcile(symbol)) != mt5.TRADE_RETCODE_DONE:
            print(f"CloseAllError: could not reconcile {symbol}, error code={res}")


if __name__ == "__main__":
    try:
        if mt5.initialize():
            close_all()
    finally:
        mt5.shutdown()
 

Hi, I didnt understand one point.

How did you fix ( mt5.order_send() returns None )?

I have the same issue...

I tried to use ( raw_order(**kwargs) and mt5.order_send(request) ), but both return "None"

Other functions works fine ( only get information ), when I try to use order_send nothing.


是磑 佐藤:

Thank you in advance for helping me!


I'm coding automatic trading system in python.

I'd like to get positions and close them automatically.

However, mt5.order_send() returns None(not any errors but 'None'!) if request['position'] is input from pd.Series data.

When I directly input position id code, the function works.


the code is below:

*mt5_initialize() is user function that calls mt5.initialize()

*tickets[i] is the position id (int32).


MQL5 forum
MQL5 forum
  • www.mql5.com
MQL5: Forum on automated trading systems and strategy testing
 
nicholi shen:

No idea why but you really shouldn't be closing orders that way on a hedging account anyway. You would first want to flatten the position the reconcile the orders as closed using the closeby feature. 


Thanks for sharing this code ! I am able to close orders, for example a buy, by doing a sell and then doing a close_by...but when I look at the history of the deals these operations are missing


do you also have this problem?

from_date=dt.datetime(2000,1,1)

to_date=dt.datetime.now()


history_deals=mt5.history_deals_get(from_date, to_date)

history_deals_df=pd.DataFrame(list(history_deals),columns=history_deals[0]._asdict().keys())