Recently, more and more TradingView users have connected the TradingView chart signal to FMZ platform (FMZ.COM) and let the robot strategy on FMZ execute the transaction according to the chart signal, which saves a lot of code writing and design work. Directly, indicators can be used for programmatic and automated trading, which reduces the barriers for many programmatic and quantitative trading development. There are several design schemes for realizing automatic trading on TradingViewWebHook
.
The previous solution: https://www.fmz.com/digest-topic/5533.
The previous plan was to extend the API interface of FMZ Platform to send instructions to the robot. Today, let’s take a look at another solution. Let TradingView’s alarm WebHook request be sent directly to the FMZ platform robot, so that it can directly send instructions and order robot transactions.
The strategy is written in Python. After the robot is created and started using this strategy, the robot will create a thread, which will start a service to monitor the set port. Waiting for external requests and processing. When I tested it, it was tested by the host on the server, and the device where the host is located must be accessible from the outside. When the robot executes the transaction, it uses the market order interface. in addition, this strategy can also be modified to implement the limit order
order logic. In order to be easy to understand and streamlined, the market order is used here, so the exchange must support the market order.
'''
Request format: http://x.x.x.x:xxxx/data?access_key=xxx&secret_key=yyy&type=buy&amount=0.001
Strategy robot parameters:
- Type: Encrypted string, AccessKey, SecretKey, you can use the low-privileged API KEY of the FMZ platform, or you can generate the KEY yourself.
- Type: string, contract ID, ContractType
- Type: numeric value, port number, Port
'''
import _thread
import json
from http.server import HTTPServer, BaseHTTPRequestHandler
from urllib.parse import parse_qs, urlparse
def url2Dict(url):
query = urlparse(url).query
params = parse_qs(query)
result = {key: params[key][0] for key in params}
return result
class Executor(BaseHTTPRequestHandler):
def do_POST(self):
try:
self.send_response(200)
self.send_header("Content-type", "application/json")
self.end_headers()
dictParam = url2Dict(self.path)
# check
if len(dictParam) == 4 and dictParam["access_key"] == AccessKey and dictParam["secret_key"] == SecretKey:
del dictParam["access_key"]
del dictParam["secret_key"]
Log("Request received", "parameter:", dictParam, "#FF0000")
'''
map[access_key:xxx amount:0.001 secret_key:yyy type:buy]
'''
isSpot = True
if exchange.GetName().find("Futures") != -1:
if ContractType != "":
exchange.SetContractType(ContractType)
isSpot = False
else :
raise "No futures contract set"
if isSpot and dictParam["type"] == "buy":
exchange.Buy(-1, float(dictParam["amount"]))
Log(exchange.GetAccount())
elif isSpot and dictParam["type"] == "sell":
exchange.Sell(-1, float(dictParam["amount"]))
Log(exchange.GetAccount())
elif not isSpot and dictParam["type"] == "long":
exchange.SetDirection("buy")
exchange.Buy(-1, float(dictParam["amount"]))
Log("Holding Position:", exchange.GetPosition())
elif not isSpot and dictParam["type"] == "short":
exchange.SetDirection("sell")
exchange.Sell(-1, float(dictParam["amount"]))
Log("Holding Position:", exchange.GetPosition())
elif not isSpot and dictParam["type"] == "cover_long":
exchange.SetDirection("closebuy")
exchange.Sell(-1, float(dictParam["amount"]))
Log("Holding Position:", exchange.GetPosition())
elif not isSpot and dictParam["type"] == "cover_short":
exchange.SetDirection("closesell")
exchange.Buy(-1, float(dictParam["amount"]))
Log("Holding Position:", exchange.GetPosition())
# Write data response
self.wfile.write(json.dumps({"state": "ok"}).encode())
except Exception as e:
Log("Provider do_POST error, e:", e)
def createServer(host):
try:
server = HTTPServer(host, Executor)
Log("Starting server, listen at: %s:%s" % host)
server.serve_forever()
except Exception as e:
Log("createServer error, e:", e)
raise Exception("stop")
def main():
# Start a thread
try:
_thread.start_new_thread(createServer, (("0.0.0.0", Port), )) # Test on VPS server
except Exception as e:
Log("Error message:", e)
raise Exception("stop")
Log("Account asset information:", _C(exchange.GetAccount))
while True:
LogStatus(_D())
Sleep(2000)
TradingView’s WebHook alarm request
The alarm request setting is:
http://xxx.xxx.xxx.xxx:80/data?access_key=e3809e173e23004821a9bfb6a468e308&secret_key=45a811e0009d91ad21154e79d4074bc6&type=sell&amount=0.1
Since TradingView sends POST
requests, the monitoring service must monitor POST
requests, and TradingView only allows port 80 for the http
protocol.
xxx.xxx.xxx.xxx
is the device IP address of the host where the robot is located. Fill in the specific IP address of your own device, you need to be aware that it must be accessible from the external network.
The access_key
and secret_key
can be generated by themselves, as long as the access_key
and secret_key
in the WebHook
alarm request are the same as those configured on the robot parameters.
Type
, trading direction, buying or selling, opening or closing, note that spots and futures are distinguished. If it is a futures, note that the futures contract code must be set on the robot parameters, and the configured exchange object needs to be a futures exchange.
amount
, the number of transactions.
Use wexApp
to simulate the real market test.
Full strategy address: https://www.fmz.com/strategy/221850
The access_key
and secret_key
in the scheme are only for identification, and there is no security for using http
. This solution is just an idea and an introduction. In practical applications, security considerations should be added and https
communication should be used.