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"...
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()
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()
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).
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())
- Free trading apps
- Over 8,000 signals for copying
- Economic news for exploring financial markets
You agree to website policy and terms of use
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).