Algorithmic Trading is allegedly fairly common, however almost kept behind lock and key for the majority of the non-technical public. Retail Traders appear to focus more on rather manual trading strategies. I love automation. So lets take a crack at it.
Following on from the last installment. The example code was failing to run successfully with the following error:
1. order_send(): by GBPUSD 0.1 lots at 1.245 with deviation=20 points
2. order_send failed, retcode=10030
retcode=10030
deal=0
order=0
volume=0.0
price=0.0
bid=0.0
ask=0.0
comment=Unsupported filling mode
request_id=0
retcode_external=0
request=TradeRequest(action=1, magic=234000, order=0, symbol='GBPUSD', volume=0.1, price=1.245, stoplimit=0.0, sl=1.2440000000000002, tp=1.246, deviation=20, type=0, type_filling=2, type_time=0, expiration=0, comment='python script open', position=0, position_by=0)
So in the process we’re still here!:
3. Write initial test script to have Python able to interact with MT5
Looks like the error arises due to the defined filling moe being unsupported. Not really sure what that is. So lets give it a quick ChatGPT.
what are the supported filing modes for the mt5 python module, for subitting orders
The MetaTrader 5 (MT5) Python module provides several supported filing modes for submitting orders. These filing modes determine how orders are executed and processed by the trading platform. The available filing modes are:
ORDER_FILLING_FOK (Fill or Kill): This mode requires the entire order to be executed immediately and completely; otherwise, it will be canceled.
ORDER_FILLING_IOC (Immediate or Cancel): This mode executes the order partially or completely, but any portion that cannot be executed immediately will be canceled.
ORDER_FILLING_RETURN (Return): This mode allows partial order execution. Any portion of the order that cannot be executed immediately remains in the order book until it is executed or canceled manually.
ORDER_FILLING_RESERVED (Reserved): This mode is used for internal purposes and is not available for regular trading operations.
When submitting an order using the MT5 Python module, you need to specify the desired filing mode as a parameter in the order request. For example, if you want to submit an order with Fill or Kill mode, you would set the filing mode as ORDER_FILLING_FOK in the order request.
Please note that the availability and behavior of these filing modes may vary depending on the specific broker and trading environment you are using with the MT5 platform. It's always a good idea to consult the documentation or API reference of your broker or the MT5 Python module for the most accurate and up-to-date information regarding filing modes and their usage.
So, lets try changing the line
mt5.ORDER_FILLING_RETURN
to
mt5.ORDER_FILLING_IOC
instead.
Progress!
Order opened and Closed Successfully. Woo!
python3 .\exampleconnect.py
MetaTrader5 package author: MetaQuotes Ltd.
MetaTrader5 package version: 5.0.45
1. order_send(): by GBPUSD 0.1 lots at 1.245 with deviation=20 points
2. order_send done, OrderSendResult(retcode=10009, deal=285100830, order=394540683, volume=0.1, price=1.245, bid=1.24491, ask=1.245, comment='Request executed', request_id=1157830844, retcode_external=0, request=TradeRequest(action=1, magic=234000, order=0, symbol='GBPUSD', volume=0.1, price=1.245, stoplimit=0.0, sl=1.2440000000000002, tp=1.246, deviation=20, type=0, type_filling=1, type_time=0, expiration=0, comment='python script open', position=0, position_by=0))
opened position with POSITION_TICKET=394540683
sleep 2 seconds before closing position #394540683
3. close position #394540683: sell GBPUSD 0.1 lots at 1.24491 with deviation=20 points
4. position #394540683 closed, OrderSendResult(retcode=10009, deal=285100831, order=394540686, volume=0.1, price=1.24491, bid=1.24491, ask=1.245, comment='Request executed', request_id=1157830845, retcode_external=0, request=TradeRequest(action=1, magic=234000, order=0, symbol='GBPUSD', volume=0.1, price=1.24491, stoplimit=0.0, sl=0.0, tp=0.0, deviation=20, type=1, type_filling=1, type_time=0, expiration=0, comment='python script close', position=394540683, position_by=0))
retcode=10009
deal=285100831
order=394540686
volume=0.1
price=1.24491
bid=1.24491
ask=1.245
comment=Request executed
request_id=1157830845
retcode_external=0
request=TradeRequest(action=1, magic=234000, order=0, symbol='GBPUSD', volume=0.1, price=1.24491, stoplimit=0.0, sl=0.0, tp=0.0, deviation=20, type=1, type_filling=1, type_time=0, expiration=0, comment='python script close', position=394540683, position_by=0)
traderequest: action=1
traderequest: magic=234000
traderequest: order=0
traderequest: symbol=GBPUSD
traderequest: volume=0.1
traderequest: price=1.24491
traderequest: stoplimit=0.0
traderequest: sl=0.0
traderequest: tp=0.0
traderequest: deviation=20
traderequest: type=1
traderequest: type_filling=1
traderequest: type_time=0
traderequest: expiration=0
traderequest: comment=python script close
traderequest: position=394540683
traderequest: position_by=0
Cleaning up code is always good, to make is more adaptable, readable, and generally put you in a good spot for debugging.
I haven’t added comments here but have added some print statements and seperated the example code into functions to be called instead of a single sequence of steps.
This here would be an example of the adapted openPosition
function. The final program will likely operate an analysis within a while True:
loop, making it constantly reassess the algorithm and goods like that.
def openPosition(symbol, price):
connectToMetaTrader()
if SENDING_ORDER:
return
SENDING_ORDER = True
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": 17829,
"comment": "Open Order",
"type_time": mt5.ORDER_TIME_GTC,
"type_filling": mt5.ORDER_FILLING_IOC,
}
ORDERS.append(mt5.order_send(request))
print("[info] openPosition |Sent Order:\n\tSymbol: {} \n\tLots: {} \n\tPrice: {}".format(symbol,lot,price));
if ORDERS[-1].retcode != mt5.TRADE_RETCODE_DONE:
print("[error] openPosition | order_send failed, retcode={}".format(ORDERS[-1].retcode))
result_dict=result._asdict()
for field in result_dict.keys():
print(" {}={}".format(field,result_dict[field]))
if field=="request":
traderequest_dict=result_dict[field]._asdict()
for tradereq_filed in traderequest_dict:
print("[error] openPosition | traderequest: {}={}".format(tradereq_filed,traderequest_dict[tradereq_filed]))
print("[info] openPosition | shutdown() and quit")
disconnectFromMetaTrader()
SENDING_ORDER = False
print("[info] openPosition | order_send done, ", ORDERS[-1])
print("[info] openPosition | opened position with POSITION_TICKET={}".format(ORDERS[-1].order))
print("[info] openPosition | sleep 2 seconds before closing position #{}".format(ORDERS[-1].order))
Adding version control to your code gives a lot of benefits, even if not pushed to a remote repository. The ability to see changes in code between intervals of progress can give much benefit. In my case, I have a github account, and I already have access set up via an ssh key, and so pushing to a new remote repository is straight forward, so I’ve done it.
Checkout my public repos and contributions at Github - thishaseeb.
Worth noting, my professinal work is not under this user, so it’s not an accurate representation of the work I’ve done over the last few years!
Algorithm Design.
It’s time to get the strategy on paper in diagram form and in a manner which will make it straight forwards, or reasonable straight forward to put into code!
~H
2023-05-12