[TOC] This tutorial contains a basic knowledge of strategy writing, including API introduction, review, charting, etc. After learning this basic tutorial, the user will be able to use the basic API proficiently to write a stable desktop strategy.FMZ inventors use the quantification platform to get started 。
The old version of the tutorial:Inventors quantify (FMZ.COM) strategies written entirely using Manual 2.0 (tutorials)This tutorial lists many indexed posts, and I recommend browsing through them.
Programmatic trading is the use of a program to connect an API to an exchange to automatically buy and sell or perform other functions as intended by the design.
Currently, there are two main types of interface protocols for digital currency exchanges: REST and Websocket. The REST protocol requires one access for each data retrieval.
{"data:{"buy":"11351.73","high":"11595.77","last":"11351.85","low":"11118.45","open":"11358.74","quoteVol":"95995607137.00903936","sell":"11356.02","time":1565593489318,"vol":"3552.5153"}}
This will show you the latest market for transactions with BTC_USDT pairs, which will change with each update.market=
Then there are the specific transaction parameters, which can be modified to obtain other transaction data. For public interfaces, such as marketplaces, everyone can access them, so no verification is needed, while some interfaces require user authentication, which requires signing using API-KEY. Websocket is a subscription mode, after sending the content that needs to be subscribed, the exchange sends the updated data to the program, without having to re-access each time, so it is more efficient.
The FMZ Quantitative Trading Platform encapsulates the REST interface of the various exchanges, using a unified way of calling and data formatting to make the writing of policies more simple and general. The FMZ platform can easily support Websocket, which will be explained in detail in the next tutorial.
The FMZ platform API documentation is largely based on JavaScript, but due to the packaging, there is little difference between the different languages, just need to pay attention to the grammar problem. C++ is slightly special, later tutorials will have a dedicated introduction. Since Js is relatively simple and has no compatibility problems, it is recommended for beginners to use. FMZ quantification platform supports full Python, free installation of various packages, it is recommended to have a certain programming basics.
Since there are different versions of Python, it is possible to specify at the beginning of the program, such as#!Python2
,#!Python3
Note that JavaScript has recently upgraded its ES6 syntax, which is interesting to learn. The following shows Python and Javascript code with the same functionality, with only syntax differences, so the API documentation only gives examples of Javascript, and this tutorial will also take into account Python's special use cases.
#python代码
def main():
while True:
Log(exchange.GetAccount().Balance)
Sleep(2000)
#相应的Js代码
function main(){
while(true){
Log(exchange.GetAccount().Balance)
Sleep(2000)
}
}
The FMZ Quantification Platform provides a debug tool for debugging the API interfaces.https://www.fmz.com/m/debugThe debugger only supports JavaScript, can only be executed for a period of time, and can debug the exchange interface without creating a physical disk. The return data will be returned as a result, and the debugger's code will not be saved.
Policy programs, like normal programs, are executed in code sequence, with the exception that there must be a main function. Because policies need to run continuously, a loop is usually required plus a sleep period. Because all API accesses to transactions have a limited frequency, a corresponding sleep period needs to be adjusted. This architecture is a typical fixed-interval execution, and websockt can also be used to write event-driven policies, such as those that execute immediately when there is a change in depth.
Other functions with special functions are:
function onTick(){
var ticker = exchange.GetTicker()
var account = exchange.GetAccount()
//在这里写策略逻辑,将会每6s调用一次
}
function main(){
while(true){
onTick()
Sleep(6000)
}
}
In the previous example, if a network access error causes the policy to be stopped directly, if you want a similar policy that does not stop automatically, you can use the real-time policy try catch to allow error master loop. Of course, this is only recommended when the policy is stable, otherwise it will not return all errors, difficult to sort the policy problem.
function onTick(){
var ticker = exchange.GetTicker()
var account = exchange.GetAccount()
//在这里写策略逻辑,将会每6s调用一次
}
function main(){
try{
while(true){
onTick()
Sleep(6000)
}
}catch(err){
Log(err)
}
}
When calling any exchange-related API, the exchange and the transaction pair are required to be explicit.exchange
It represents the object.exchange.GetTicker()
The result will be the market ticker of this exchange-trading pair.
The FMZ platform supports the addition of multiple exchange-traded pairs at the same time, such as BTC and ETH from the same exchange account, or BTC from one exchange and ETH from another exchange. Note that different accounts from the same exchange can also be added at the same time, depending on the label added to the FMZ website.exchanges
Arrays are represented by the order in which they are added to the disk.exchanges[0]
、exchanges[1]
... and so on. The format of the trading pair is as follows:BTC_USDT
The former is BTC as a trading currency, the latter is USDT as a billing currency.
Obviously, this would be a hassle if we were to operate a lot of pairs of transactions, at which point we could use SetCurrency to swap pairs of transactions, such asexchange.SetCurrency("BTC_USDT")
At this time,exchange
The transaction pairs that are tied are converted toBTC_USDT
This will remain in effect until the next call to change the trade pair.Note that retesting the latest supported switching pairsThe following is a concrete example.
var symbols = ["BTC_USDT", "LTC_USDT", "EOS_USDT", "ETH_USDT"]
var buyValue = 1000
function main(){
for(var i=0;i<symbols.length;i++){
exchange.SetCurrency(symbols[i])
var ticker = exchange.GetTicker()
var amount = _N(buyValue/ticker.Sell, 3)
exchange.Buy(ticker.Sell, amount)
Sleep(1000)
}
}
As mentioned above, the market interface is generally a public interface that is accessible to everyone. Common market interfaces include: access to market ticker, access to depth depth, access to K-line records, access to transaction records trades. The market is the basis of the strategy to make trade judgments, which will be introduced one by one below, it is best to try it yourself in the debugging tool, for detailed explanations you can see the API documentation.
Each interface has its own interface.Info
Fields, representing the original data strings returned by the exchange, can be used to supplement additional information that needs to be parsed before using JavaScriptJSON.parse()
Python uses the json library.Time
The field indicates the time stamp of the request, which can be used to determine the delay.
It's possible to use an API interface on a physical disk to return a failed access.null
Python is back.None
This is very important, because it will cause errors and cause the disk to stop. This tutorial will explain it separately.
The most commonly used interface is to access the current market situation, to find out the price of the last trade, the price of a buy or sell, the most recent volume of trades, etc.; to determine the price of a trade based on ticker information before placing an order; an example of a real-time return.{"Info:{}, "High":5226.69, "Low":5086.37,"Sell":5210.63, "Buy":5208.5, "Last":5208.51, "Volume":1703.1245, "OpenInterest":0, "Time":1554884195976}
。
function main() {
var ticker = exchange.GetTicker()
Log(ticker) //在调试工具中 return ticker 。可以看到具体的结果。
Log('上次成交价: ',ticker.Last, '买一价: ', ticker.Buy)
}
Get deep listing information. Although GetTicker contains buy and sell listings, if you want to query deeper listings, you can use this interface to generally find the top 200 listings. You can use this interface to calculate the shock price. Below is a true return result.
{
"Info":null,
"Asks":[
{"Price":5866.38,"Amount":0.068644},
{"Price":5866.39,"Amount":0.263985},
......
]
"Bids":[
{"Price":5865.13,"Amount":0.001898},
{"Price":5865,"Amount":0.085575},
......
],
"Time":1530241857399
}
An example of how to buy and sell in depth:
function main() {
var depth = exchange.GetDepth()
Log('买一价个: ', depth.Bids[0].Price, '卖一价格: ', depth.Asks[0].Price)
}
Get a K-line, one of the most commonly used interfaces, which can return a longer period of price information at a time, calculating the basis of various indicators. K-line cycles indicate the default period when the real disk will be added if not specified. K-line lengths cannot be specified, they will continue to increase with time accumulation, up to 2000 bits, the first call is about 200 bits (different exchanges return different); the last K-line is the latest K-line, so the data will constantly change as the market trends, the first K-line is the oldest data.
exchange.SetMaxBarLen(Len)
You can set the number of first time K-lines (some exchanges support) and set the maximum number of K-lines.For example:exchange.SetMaxBarLen(500)
GetRecords can specify periods: PERIOD_M1:1 minutes, PERIOD_M5:5 minutes, PERIOD_M15:15 minutes, PERIOD_M30:30 minutes, PERIOD_H1:1 hours, PERIOD_D1:1 days. It is specifically used forexchange.GetRecords(PERIOD_M1)
The latest custodian will support custom cycles, directly transmitting cycle seconds as parameters, minute-level customization will be synthesized based on 1 minute K line, 1 minute below K line will be synthesized through GetTrades, and commodity futures will be synthesized based on ticks.Be aware that you will encounter similar problems in this tutorial.PERIOD_M1
These are the global variables that FMZ uses by default, and those interested can log their specific values and use them directly.
Returns data examples:
[
{"Time":1526616000000,"Open":7995,"High":8067.65,"Low":7986.6,"Close":8027.22,"Volume":9444676.27669432},
{"Time":1526619600000,"Open":8019.03,"High":8049.99,"Low":7982.78,"Close":8027,"Volume":5354251.80804935},
{"Time":1526623200000,"Open":8027.01,"High":8036.41,"Low":7955.24,"Close":7955.39,"Volume":6659842.42025361},
......
]
An example of an iterative K-line:
function main(){
var close = []
var records = exchange.GetRecords(PERIOD_H1)
Log('total bars: ', records.length)
for(var i=0;i<records.length;i++){
close.push(records[i].Close)
}
return close
}
Obtaining transaction data for a certain time frame (not your own transaction data) is not supported by some exchanges.
These interfaces cannot be accessed directly because they are associated with an account and require an API-KEY signature. FMZ platform has automated unification in the background, which can be used directly.
Acquire account information. One of the most commonly used interfaces requires a call before ordering to avoid insufficient balance. Returns results such as:{"Stocks":0.38594816,"FrozenStocks":0,"Balance":542.858308,"FrozenBalance":0,"Info":{}}
Where Stocks is the available balance of the trading currency of the trading pair, FrozenStocks is the freezing balance of the outstanding order, Balance is the available amount of the pricing currency, and FrozenBalance is the freezing balance of the trading pair.BTC_USDT
In the case of Bitcoin, stocks refer to BTC and balance refers to USDT.
Note that the returned result is the result of a specified transaction pair, the information for other currencies in the transaction account is in the Info field, and it is not necessary to call multiple transaction pairs.
A continuously printed physical plate of the current transaction to the total value:
function main(){
while(true){
var ticker = exchange.GetTicker()
var account = exchange.GetAccount()
var price = ticker.Buy
var stocks = account.Stocks + account.FrozenStocks
var balance = account.Balance + account.FrozenBalance
var value = stocks*price + balance
Log('Account value is: ', value)
LogProfit(value)
Sleep(3000)//sleep 3000ms(3s), A loop must has a sleep, or the rate-limit of the exchange will be exceed
//when run in debug tool, add a break here
}
}
Payment is made.exchange.Buy(Price, Amount)
Orexchange.Buy(Price, Amount, Msg)
,Price is price,Amount is quantity,Msg is an additional string that can be displayed in the real disk log, not a must. This method is for listings, if it is not possible to complete the order immediately, it will generate an unfinished order, the order successfully returns the result as order id, failure as order id.null
, which is used to query the order status.
If you want to buy at the market price, Price is -1, Amount is the order value, such asexchange.Buy(-1, 0.5)
Yes, the deal.ETH_BTC
In the case of the ETH market, it is the market price of 0.5BTC. Some exchanges do not support market price lists and futures retrospectives.
All price and quantity precision requirements for partial transactions are available_N()
Precision functions to control. Buy and Sell have additional meanings for futures trading, which will be discussed separately.
One example of buying at the right price:
function main(){
while(true){
var ticker = exchange.GetTicker()
var price = ticker.Sell
if(price >= 7000){
exchange.Buy(_N(price+5,2), 1, 'BTC-USDT')
break
}
Sleep(3000)//Sleep 3000ms
}
Log('done')
}
The parameters of the buy order are the same as those of the buy order. The parameters of the market order are different.exchange.Sell(-1, 0.2)
In addition, the company is selling 0.2 ETH at the market price.
Order information based on the order id.exchange.GetOrder(OrderId)
OrderId is the order id, which is returned when the order is placed.Pay attention to the order typeType
Fields and order statusStatus
The actual values are numeric and represent different meanings, but unfavorable for memory, FMZ uses global constants to represent these values, such as those for outstanding orders.Status
So this is equal to 0.ORDER_STATE_PENDING
All of these global constants can be viewed in the documentation.It returns the results:
{
"Id":125723661, //订单id
"Amount":0.01, //订单数量
"Price":7000, //订单价格
"DealAmount":0, //已成交数量
"AvgPrice":0, //成交均价
"Status":0, // 0:未完全成交, 1:已成交, 2:已撤单
"Type":1,// 订单类型,0:买单, 1:卖单
"ContractType":"",//合约类型,用于期货交易
"Info":{} //交易所返回原始信息
}
}
A strategy for buying a specified number of currencies:
function main(){
while(true){
var amount = exchange.GetAccount().Stocks
var ticker = exchange.GetTicker()
var id = null
if(5-amount>0.01){
id = exchange.Buy(ticker.Sell, Math.min(5-amount,0.2))
}else{
Log('Job completed')
return //return the main function, bot will stop
}
Sleep(3000) //Sleep 3000ms
if(id){
var status = exchange.GetOrder(id).Status
if(status == 0){ //这里也可以用 status == ORDER_STATE_PENDING 来判断。
exchange.CancelOrder(id)
}
}
}
}
Retrieves current transaction lists for all pending orders. Returns empty arrays if no pending orders are found. Returns order list specific results such as GetOrder.
Examples of cancelling current transactions for all orders:
function CancelAll(){
var orders = exchange.GetOrders()
for(var i=0;i<orders.length;i++){
exchange.CancelOrder(orders[i].Id) // cancel order by orderID
}
}
function main(){
CancelAll()
while(true){
//do something
Sleep(10000)
}
}
Order ID canceled ordered.exchange.CancelOrder(OrderId)
⇒ Cancel successfully returns true, otherwise returns false. ⇒ Note that the order has been fully transacted and will be canceled if it fails.
Digital currency futures trading and spot trading are different, the above functions of spot trading are also applicable to futures, single futures trading has its own functions. Before proceeding with digital currency futures programmatic trading, it is necessary to be familiar with the manual operation on the website, understand the basic concepts, such as opening positions, even positions, full positions, even positions, leverage, even positions, floating income, collateral, and the corresponding calculation formula.
A perpetual contract is similar to a futures contract, except that there is no concept of simultaneous holding of multiple vacancies.
If an exchange supports both spot futures, such as OKEX and Huobi futures, it is necessary to select the OKEX futures tab and the Huobi futures tab separately in the exchange interface, which is considered a different exchange from the spot in FMZ.
The first step in futures trading is to set up the contract to be traded, for example OKEX futures, to create a live or retested BTC trading pair, and to set the contract in the code to be the same week, next week or quarterly.invalid contract type
。Unlike spot trading, futures contracts are often traded with a currency such as BTC as collateral, and the trading pair adding BTC usually represents a BTC_USD trading pair that is backed by BTC, and if there is a USDT-backed futures contract, it is necessary to create a real-world BTC_USDT trading pair.After setting up the trading pair, you also need to set up specific contract types, such as permanent, same week, next week, etc. After setting up the contract, you can carry out operations such as buying and selling.
There are contracts in the form of Binance, OKEX, HuobiDM, etc. that are both in the form of coins and USDT, and a distinction needs to be made when adding a real-time setup contract.
//OKEX期货
exchange.SetContractType("swap") // 设置为永续合约
exchange.SetContractType("this_week") // 设置为当周合约
exchange.SetContractType("next_week") // 设置为次周合约
exchange.SetContractType("quarter") // 设置为季度合约
//HuobiDM
exchange.SetContractType("this_week") // 设置为当周合约
exchange.SetContractType("next_week") // 设置为次周合约
exchange.SetContractType("quarter") // 设置为季度合约
exchange.SetContractType("swap") // 设置为永续合约
//币安期货
exchange.SetContractType("swap") // 设置为永续合约,注意币本位和USDT本位都存在永续
exchange.SetContractType("quarter") // 设置为当季合约
exchange.SetContractType("next_quarter") // 设置为次季合约
//BitMEX
exchange.SetContractType("XBTUSD") // 设置为永续合约
exchange.SetContractType("XBTM19") // 具体某个时间结算的合约,详情登录BitMEX查询各个合约代码
//GateIO
exchange.SetContractType("swap") // 设置为永续合约,不设置默认为swap永续合约。
//Deribit
exchange.SetContractType("BTC-27APR18") // 具体某个时间结算的合约,详情参看Deribit官网。
To get a list of current holdings, OKEX (OKCOIN) futures can be passed a parameter specifying the type of contract to be acquired. If no holdings, return blank list[]
The information returns as follows: There is a lot of specific information, which needs to be combined with transactional analysis.
Type of data | Variable name | Explained |
---|---|---|
object | Info | The original structure returned to the exchange |
number | MarginLevel | The leverage size, OKCoin is 10 or 20, OK futures' full-stock mode returns to a fixed 10, because the native API does not support |
number | Amount | Holdings, OKCoin represents the number of contracts (an integer greater than 1) |
number | FrozenAmount | Freezing of the position |
number | Price | Holding equity |
number | Margin | Freeze the security |
number | Profit | Commodity futures: Holding market loss, digital currency: ((Digital currency unit: BTC/LTC, traditional futures unit: RMB, note: OKCoin futures refer to the realisation of a surplus in the case of a full-stock, not holding market loss, under-trading refers to holding stock loss) |
const | Type | PD_LONG is a multi-head position (with closebuy_today in CTP), PD_SHORT is a blank position (with close-sell_today in CTP), PD_LONG_YD is a multi-head position (with close-buy in CTP), PD_SHORT_YD is a blank position (with close-sell in CTP) |
string | ContractType | Commodity futures are contract codes, stocks are exchange codes _ stock codes are codes, input type of specific parameters SetContractType |
function main(){
exchange.SetContractType("this_week");
var position = exchange.GetPosition();
if(position.length>0){ //特别要注意引用前要先判断position长度再引用,否则会出错
Log("Amount:", position[0].Amount, "FrozenAmount:", position[0].FrozenAmount, "Price:",
position[0].Price, "Profit:", position[0].Profit, "Type:", position[0].Type,"ContractType:", position[0].ContractType)
}
}
The first thing you need to do is set the leverage size and how to call it:exchange.SetMarginLevel(10)
In this case, the leverage is 10 times the leverage, and the leverage size of the specific supported leverage is 10 times the leverage.Note that the leverage must be set on the exchange, and the code must be consistent with the exchange's setup, otherwise there will be errors.│ can also be unset, using the default lever │
Then set the transaction direction and call mode:exchange.SetDirection(Direction)
, which corresponds to the open position position, ** unlike futures, if a perpetual contract does not have the concept of simultaneously holding multiple vacancies, i.e. does not allow a single position to be held, doing multiple openings will automatically flatten multiple positions, all only need to be setbuy
andsell
Yes. If it supports bidirectional holding, it needs to be set.closebuy
,closebuy
◦** Specific relationship:
Operating | Parameters for SetDirection | Subscript functions |
---|---|---|
More stores | exchange.SetDirection(“buy”) | exchange.Buy() |
Plain stock | exchange.SetDirection(“closebuy”) | exchange.Sell() |
Opened warehouse | exchange.SetDirection(“sell”) | exchange.Sell() |
Flat warehouse | exchange.SetDirection(“closesell”) | exchange.Buy() |
Finally, there is a specific open position code, which differs from one exchange to another, such as huobi futures are by number of listings, one for $100. Note that futures retrospectives do not support market listings.
function main(){
exchange.SetContractType("this_week") // 举例设置 为OKEX期货 当周合约
price = exchange.GetTicker().Last
exchange.SetMarginLevel(10) //设置杠杆为10倍
exchange.SetDirection("buy") //设置下单类型为做多
exchange.Buy(price+10, 20) // 合约数量为20下单
pos = exchange.GetPosition()
Log(pos)
Log(exchange.GetOrders()) //查看是否有未成交订单
exchange.SetDirection("closebuy"); //如果是永续合约,直接设置exchange.SetDirection("sell")
exchange.Sell(price-10, 20)
}
Below is a specific example of a strategy for a full-fledged breakeven.
function main(){
while(true){
var pos = exchange.GetPosition()
var ticker = exchange.GetTicekr()
if(!ticker){
Log('无法获取ticker')
return
}
if(!pos || pos.length == 0 ){
Log('已无持仓')
return
}
for(var i=0;i<pos.length;i++){
if(pos[i].Type == PD_LONG){
exchange.SetContractType(pos[i].ContractType)
exchange.SetDirection('closebuy')
exchange.Sell(ticker.Buy, pos[i].Amount - pos[i].FrozenAmount)
}
if(pos[i].Type == PD_SHORT){
exchange.SetContractType(pos[i].ContractType)
exchange.SetDirection('closesell')
exchange.Buy(ticker.Sell, pos[i].Amount - pos[i].FrozenAmount)
}
}
var orders = exchange.Getorders()
Sleep(500)
for(var j=0;j<orders.length;j++){
if(orders[i].Status == ORDER_STATE_PENDING){
exchange.CancelOrder(orders[i].Id)
}
}
}
}
It is necessary to switch to a leverage account in the code, otherwise it is the same as a spot transaction.
Useexchange.IO("trade_margin") Switching to a margin account mode, placing an order, obtaining the account assets will access the leverage interface of the exchange. Useexchange.IO("trade_normal") Switch back to normal account mode.
Supported exchanges:
Commodity futures trading and digital currency futures trading are very different. Firstly, commodity futures have a short trading time, digital currency trading 24h; the protocol for commodity futures is also not a commonly used REST API; commodity futures have a trading frequency and number of pending orders limit, while digital currency is very loose, etc. Therefore, trading commodity futures has many areas that require special attention, and it is recommended to have a rich manual operation experience. FMZ supports simnow commodity futures simulation disk, reference:https://www.fmz.com/bbs-topic/325The Commodity Futures Company added:https://www.fmz.com/bbs-topic/371
Commodity futures and in June 2019 implemented the regulatory process, individual programmed individual users of the opening of the futures traders to apply for authorization codes (specific application required information template can be sent in the WeChat group or QQ group), generally takes 4-5 days, the steps are more cumbersome. FMZ quantified platform as a programmed trading provider to each futures service provider to apply for software license codes, users can use directly without applying, in the addition of futures traders is a search for the look-alike template can see the list of FMZ has applied for.https://www.fmz.com/bbs-topic/3860If your futures broker is no longer on the list, you can only apply yourself, or re-open an account with a supported trader, which usually takes 2 days. FMZ has an in-depth partnership with some service providers, such as Qian Taijunan Macrosource Futures, which has purchased the institutional version of the FMZ platform, which can be used by users, the opener automatically becomes a VIP, and the processing fee is minimal.https://www.fmz.com/bbs-topic/506 。
Due to the advantages of the FMZ platform architecture, users can also add multiple futures accounts and implement some functions that cannot be completed by other commodity futures programmatic trading software, such as synthesis of high-frequency ticks, see:https://www.fmz.com/bbs-topic/1184
Firstly, since it is not a 24-hour transaction and requires a landing operation, it is necessary to judge the link status before making a transaction.exchange.IO("status")
For thetrue
This indicates that the exchange is connected. If the login is not successful, call the API without prompting the login button. You can sleep after the policy starts._C(exchange.SetContractType,"MA888")
This will ensure a successful landing.
The market acquisition and trading codes for commodity futures are the same as for digital currency futures, and the differences and areas of concern will be discussed here.
function main(){
_C(exchange.SetContractType,"MA888") //没登陆成功是无法订阅合约的,最好重试一下
while(true){
if(exchange.IO("status")){
var ticker = exchange.GetTicker()
Log("MA888 ticker:", ticker)
LogStatus(_D(), "已经连接CTP !")//_D获取事件
} else {
LogStatus(_D(), "未连接CTP !")
Sleep(1000)
}
}
}
It is recommended to use the commodity futures library (see below) for trading, where the code is very simple and does not need to handle cumbersome details.https://www.fmz.com/strategy/57029
function main() {
// 使用了商品期货类库的CTA策略框架
$.CTA(Symbols, function(st) {
var r = st.records
var mp = st.position.amount
var symbol = st.symbol
/*
r为K线, mp为当前品种持仓数量, 正数指多仓, 负数指空仓, 0则不持仓, symbol指品种名称
返回值如为n:
n = 0 : 指全部平仓(不管当前持多持空)
n > 0 : 如果当前持多仓,则加n个多仓, 如果当前为空仓则平n个空仓,如果n大于当前持仓, 则反手开多仓
n < 0 : 如果当前持空仓,则加n个空仓, 如果当前为多仓则平n个多仓,如果-n大于当前持仓, 则反手开空仓
无返回值表示什么也不做
*/
if (r.length < SlowPeriod) {
return
}
var cross = _Cross(TA.EMA(r, FastPeriod), TA.EMA(r, SlowPeriod));
if (mp <= 0 && cross > ConfirmPeriod) {
Log(symbol, "金叉周期", cross, "当前持仓", mp);
return Lots * (mp < 0 ? 2 : 1)
} else if (mp >= 0 && cross < -ConfirmPeriod) {
Log(symbol, "死叉周期", cross, "当前持仓", mp);
return -Lots * (mp > 0 ? 2 : 1)
}
});
}
Commodity futures use the CTP protocol, where all markets and order transactions are notified only when there is a change, while querying orders, accounts, holdings is an active query. It is therefore suitable for writing event-driven high frequency policies.GetTicker
、GetDepth
、GetRecords
All the data are cached to get the latest data, and when there is no data, it will always wait for the data, so the strategy can not sleep. When there is a change in the market, ticker, depth, records are updated, at this time call any interface will be immediately returned, the state of the interface called is set to wait for the update mode, the next time the same interface is called, it will wait for the new data to return.
If you want to access data every time you access a market, even old data, you can switch to a market instant update mode.exchange.IO("mode", 0)
The policy cannot be written as event-driven at this point, and a SLEEP event needs to be added to avoid a fast dead loop. Some low-frequency policies can use this pattern, and the policy design is simple.exchange.IO("mode", 1)
You can switch back to the default caching mode.
When operating a single contract, the default mode can be used. However, if there are multiple contracts, it is possible that one contract does not update the market, causing access to the market interface to be clogged, and other contracts do not receive market updates. To solve this problem, you can use the immediate update mode, but it is not convenient to write a high-frequency policy.exchange.IO("wait")
◦ If multiple exchange objects are added, this is rare in commodity futures, and can be usedexchange.IO("wait_any")
In this case, the returned Index will indicate the returned exchange index.
This is the first time I've seen this in my life.{Event:"tick", Index:交易所索引(按实盘上交易所添加顺序), Nano:事件纳秒级时间, Symbol:合约名称}
The order was sent to:{Event:"order", Index:交易所索引, Nano:事件纳秒级时间, Order:订单信息(与GetOrder获取一致)}
At this point, the strategy structure can be written as:
function on_tick(symbol){
Log("symbol update")
exchange.SetContractType(symbol)
Log(exchange.GetTicker())
}
function on_order(order){
Log("order update", order)
}
function main(){
while(true){
if(exchange.IO("status")){ //判断链接状态
exchange.IO("mode", 0)
_C(exchange.SetContractType, "MA888")//订阅MA,只有第一次是真正的发出订阅请求,接下来都是程序切换,不耗时间。
_C(exchange.SetContractType, "rb888")//订阅rb
while(true){
var e = exchange.IO("wait")
if(e){
if(e.event == "tick"){
on_tick(e.Symbol)
}else if(e.event == "order"){
on_order(e.Order)
}
}
}
}else{
Sleep(10*1000)
}
}
}
It is also worth noting the difference between commodity futures and digital currency exchanges. GetDepth, for example, actually has only one file depth (the 5 file depth fees are expensive), and GetTrades does not access the transaction history (all simulated based on stock changes, with no real transaction records). Commodity futures have a drop-off limit, where the price of the deep sell order is the drop-off price, the order volume is 0, the price of the buy order is the drop-off price, the order volume is 0; there is also a frequency of commodity futures query interface, access to accounts, orders, positions, such as strict limits, generally 2s.
exchange.IO("instruments"): Returns a list of all contracts on the exchange in the form of a dictionary.exchange.IO("products"): Returns a list of all products on the exchange in the dictionary format {product name: details}; supports only physical disks.exchange.IO("subscribed"): Returns a subscribed market contract, in the same format, only supports physical displays.
Traditional CTP futures have beenContractType
This is the ID of the contract, which is written in small letters.exchange.SetContractType("au1506")
The contract setup successfully returns details of the contract, such as how much to buy at least once, the handling fee, the delivery time, etc. When subscribing to multiple contracts, only the first time is the real sending of the subscription request, and then it is only a switch to the transaction pair at the code level, without taking time. The main continuous contract is code 888 such as MA888, the continuous index contract is 000 such as MA000, 888 and 000 only support retrieval for virtual contract transactions, the physical disk only supports obtaining transactions.However, the Mac language can operate a master contract, and the program automatically swaps positions, i.e. it flatens the non-major position and opens a new position on the main position.
Unlogged successfully fails to set up the contract, but it also returns immediately, so you can try again with _C, knowing that the CTP login is complete. Once the login is successful, resetting the contract is not time-consuming and will not result in real network access.
SetDirection
The direction can be takenbuy, closebuy, sell, closesell
Four parameters, more commodity futuresclosebuy_today
andclosesell_today
I'm not sure what you're talking about.closebuy/closesell
For the futures, only the varieties of the previous period can be distinguished from the current and the past, which may affect the transaction fees, so the preference should be given to the past. For CTP traditional futures, the second parameter can be set to 1 or 2 or 3, respectively, to set the default speculation.The specific operations of buying and selling, taking positions, obtaining orders, withdrawals, obtaining accounts, etc. are the same as in digital currency futures trading.
Operating | Parameters for SetDirection | Subscript functions |
---|---|---|
More stores | exchange.SetDirection(“buy”) | exchange.Buy() |
Plain stock | exchange.SetDirection(“closebuy”) | exchange.Sell() |
Opened warehouse | exchange.SetDirection(“sell”) | exchange.Sell() |
Flat warehouse | exchange.SetDirection(“closesell”) | exchange.Buy() |
The following example is a specific placement function, note that this example is too simple, but also consider a series of questions such as whether the transaction is at the time of the transaction, how to retry the pending order, how much is the maximum order quantity, whether the frequency is too high, specifically whether the price is slipping or discontinuing, etc. For reference only.The open equity trading platform recommends using a well-packaged class library.https://www.fmz.com/strategy/12961The class library section contains specific information, and it is recommended to learn the source code of the class library.
function Cover(contractType, amount, slide) {
for (var i = 0; i < positions.length; i++) {
if (positions[i].ContractType != contractType) {
continue;
}
var depth = _C(e.GetDepth);
if (positions[i].Type == PD_LONG || positions[i].Type == PD_LONG_YD) {
exchange.SetDirection(positions[i].Type == PD_LONG ? "closebuy_today" : "closebuy");
exchange.Sell(depth.Bids[0]-slide, amount, contractType, positions[i].Type == PD_LONG ? "平今" : "平昨", 'Bid', depth.Bids[0]);
} else {
exchange.SetDirection(positions[i].Type == PD_SHORT ? "closesell_today" : "closesell");
exchange.Buy(depth.Asks[0]+slide, amount, contractType, positions[i].Type == PD_SHORT ? "平今" : "平昨", 'Ask', depth.Asks[0]);
}
}
}
Commodity futures support custom order types (live support, retest not supported) specified in a suffix-like manner, added after suffix_suffix e.g.
exchange.SetDirection("buy_ioc");
exchange.SetDirection("sell_gtd-20170111")
The specific implications are:
By default, the CTP interface is activated in commodity futures traders, which can be changed to the easy-to-use interface if required. The wrapping, the call method is the same through FMZ. The difference is that the account, order, and hold are all push modes, so the custodian maintains the data locally, and immediately returns when the corresponding interface is called, not actually issuing a request.
The ease-of-use protocol defines the order types as follows:
Log a log in the desktop interface, add the @ character after the string, and the message will be pushed into the push queue, which will be pushed directly after binding WeChat or Telegram.Log('推送到微信@')
You can also customize the color of the logsLog('这是一个红色字体的日志 #ff0000')
。#ff0000
16th order representation of RGB colors
All log files are stored in the sqlit database on the hard disk in the directory where the host is located, which can be downloaded and opened using the database software, or used to copy backup and restore (the database name is the same as the hard disk id).
Record the earnings and draw the earnings curve in the real disk interface, which can also be saved after the real disk is restarted.LogProfit(1000)
Please be careful.LogProfit
The parameters are not necessarily a gain, but can be any number that needs to be filled in.
Real-time status, since Log logs are saved first and refreshed continuously, can be used if you need an information that is only displayed but not savedLogStatus
The function ≠ ∞LogStatus
The parameters are strings and can also be used to represent table information.
An example of a table showing the location of a specific disk state:
var table = {type: 'table', title: '持仓信息', cols: ['列1', '列2'], rows: [ ['abc', 'def'], ['ABC', 'support color #ff0000']]};
LogStatus('`' + JSON.stringify(table) + '`'); // JSON序列化后两边加上`字符, 视为一个复杂消息格式(当前支持表格)
LogStatus('第一行消息\n`' + JSON.stringify(table) + '`\n第三行消息'); // 表格信息也可以在多行中出现
LogStatus('`' + JSON.stringify([table, table]) + '`'); // 支持多个表格同时显示, 将以TAB显示到一组里
LogStatus('`' + JSON.stringify(tab1) + '`\n' + '`' + JSON.stringify(tab2) + '`\n'); // 上下排列显示多个表
The parameters are milliseconds, such asSleep(1000)
Sleep for a second. Since the frequency of access to all transactions is limited, it is a general strategy to include sleep time in the dead cycle.
When the hard drive is restarted, the program will restart, and if you want to save some persistent information, you can do so by clicking on the link below._G
It is very convenient to use and can store JSON-sequenced content._G
The function is written asonexit()
This will automatically save the information you need every time you stop the policy.
If you want to save more formatted data, the _G function is not very useful and you can write directly to the database using Python.
function onexit(){
_G('profit', profit)
}
function main(){
_G("num", 1); // 设置一个全局变量num, 值为1 s
_G("num", "ok"); // 更改一个全局变量num, 值为字符串ok
_G("num", null); // 删除全局变量 num
_G("num"); // 返回全局变量num的值,如果不存在返回null
var profit = 0
if(_G('profit')){
profit = _G('profit')
}
}
In order to control price and quantity accuracy, FMZ has built-in the _N function to determine the number of decimal places to store, such as:_N(4.253,2)
The result is 4.25.
An API call to an exchange is not guaranteed to be successful every time an access is made. _C is an automatically retry function. It will continue to call the specified function until it returns success (the function returns null or false will retry), for example._C(exchange.GetTicker)
By default, the retest interval is 3 seconds, and the _CDelay function can be called to control the retest interval, e.g. _CDelay ((1000), suggesting changing the _C function's retest interval to 1 second.GetTicker()
,exchange.GetDepth
,GetTrade
,GetRecords
,GetAccount
,GetOrders
, GetOrder
All of them are error tolerant with _C, preventing access failures from causing program interruptions.
CancelOrder
Can't use the _C function because there are various reasons for cancellation failures. If a cell has been transacted, another cancellation will return a failure, and using the _C function will result in repeated attempts.
The _C function can also be used to pass parameters, and is also used for custom functions.
function main(){
var ticker = _C(exchange.GetTicker)
var depth = _C(exchange.GetDepth)
var records = _C(exchange.GetRecords, PERIOD_D1) //传入参数
}
Direct call_D()
Returns the current time string, such as:2019-08-15 03:46:14
│ returns the return time if it is a callback. │ can be used to determine the time using the _D function, such as:_D().slice(11) > '09:00:00':
_D(timestamp,fmt)
, which converts the ms timestamp to a time string, such as_D(1565855310002)
The fmt parameter is the time format, defaultyyyy-MM-dd hh:mm:ss
For some commonly used indicator functions, such as common indicators such as MA\MACD\KDJ\BOLL, the FMZ platform is directly built-in, and specific supported indicators can be found in the API documentation.
It is best to determine the length of the K-line before using the indicator function. When the previous K-line length does not meet the required cycle, the result is:null
If the input K line length is 100 and the calculation period for the MA is 10, the first 9 values are null and the next one is normal.
JavaScript also supports full talib, which is supported as a third-party library, and calls such astalib.CCI(records)
│ referencehttp://ta-lib.org/function.htmlFor Python, the talib library can be installed on its own, but it is not possible to install it simply using pip, because it needs to be compiled.
Indicator functions can be passed to arbitrary arrays in addition to K-line data
function main(){
var records = exchange.GetRecords(PERIOD_M30)
if (records && records.length > 9) {
var ma = TA.MA(records, 14)
Log(ma)
}
}
Here are some of the most common JavaScript functions on the desktop.
Date.now()
Go back to the current time frameparseFloat()
We can convert a string into a number, likeparseFloat("123.21")
parseInt()
Convert the string to an integernum.toString()
Convert numbers to strings, num to numeric variablesJSON.parse()
Formatting json strings, such asJSON.parse(exchange.GetRawJSON())
Math.max()
,Math.abs()
For example, the following are common mathematical operations:https://www.w3school.com.cn/jsref/jsref_obj_math.aspThere are a lot of situations that need to be considered to write a real-time strategy function, such as a simple function such as buying 5 coins, we have to consider: is the current balance enough? what is the price of the order? what is the precision? do not need to split orders to avoid shocking the market? how to handle unfinished orders? etc. Details.
JavaScript digital currency trading libraries and commodity futures trading libraries are built-in by default and do not require copying. Other template libraries can be found at Strategy Square.https://www.fmz.com/square/20/1You can copy and save the template library and select the library you want to use when you create your own policy.
The JavaScript template functions are all written in$
Python started withext
I'm going to start.
The source code address is:https://www.fmz.com/strategy/10989, which is built in and does not need to be copied. Implementations of specific functions can be directly referenced to the source code.
Access to the account:
$.GetAccount(e)
Log($.GetAccount()); // 获取账户信息, 带容错功能
Log($.GetAcccount(exchanges[1]));
The following withdrawal order:
$.Buy/Sell(e, amount)
$.Buy(0.3); // 主交易所买入0.3个币
$.Sell(0.2); // 主交易所卖出0.2个币
$.Sell(exchanges[1], 0.1); // 次交易所卖出0.1个币
$.CancelPendingOrders(e, orderType)
$.CancelPendingOrders(); // 取消主交易所所有委托单
$.CancelPendingOrders(ORDER_TYPE_BUY); // 取消主交易所所有的买单
$.CancelPendingOrders(exchanges[1]); // 取消第二个交易所所有订单
$.CancelPendingOrders(exchanges[1], ORDER_TYPE_SELL); // 取消第二个交易所所有的卖单
Judging by the cross:
$.Cross(periodA, periodB) / $.Cross(arr1, arr2);
var n = $.Cross(15, 30);
var m = $.Cross([1,2,3,2.8,3.5], [3,1.9,2,5,0.6])
如果 n 等于 0, 指刚好15周期的EMA与30周期的EMA当前价格相等
如果 n 大于 0, 比如 5, 指15周期的EMA上穿了30周期的EMA 5个周期(Bar)
如果 n 小于 0, 比如 -12, 指15周期的EMA下穿了30周期的EMA 12个周期(Bar)
如果传给Cross不是数组, 则函数自动获取K线进行均线计算
如果传给Cross的是数组, 则直接进行比较
This is a list of all the different ways $.withdraw (e, currency, address, amount, fee, password) is credited in the database.
$.withdraw(exchange, "btc", "0x.........", 1.0, 0.0001, "***")
Commodity futures trading library is stable and recommended to use. Source code address:https://www.fmz.com/strategy/12961│ already built-in, no need to copy │
The CTA library
function main() {
$.CTA("rb000,M000", function(r, mp) {
if (r.length < 20) {
return
}
var emaSlow = TA.EMA(r, 20)
var emaFast = TA.EMA(r, 5)
var cross = $.Cross(emaFast, emaSlow);
if (mp <= 0 && cross > 2) {
Log("金叉周期", cross, "当前持仓", mp);
return 1
} else if (mp >= 0 && cross < -2) {
Log("死叉周期", cross, "当前持仓", mp);
return -1
}
});
}
Examples of library calls
function main() {
var p = $.NewPositionManager();
p.OpenShort("MA609", 1);
p.OpenShort("MA701", 1);
Log(p.GetPosition("MA609", PD_SHORT));
Log(p.GetAccount());
Log(p.Account());
Sleep(60000 * 10);
p.CoverAll("MA609");
LogProfit(p.Profit());
Log($.IsTrading("MA609"));
// 多品种时使用交易队列来完成非阻塞的交易任务
var q = $.NewTaskQueue();
q.pushTask(exchange, "MA701", "buy", 3, function(task, ret) {
Log(task.desc, ret)
})
while (true) {
// 在空闲时调用poll来完成未完成的任务
q.poll()
Sleep(1000)
}
}
Since the original diagram functions are more complex, which will be introduced in the next tutorial, it is recommended for beginners to directly use the diagram library, very simple drawing line diagrams, K line diagrams, etc. FMZ has a built-in simple class library, which can be seen on the policy edit page, if not built-in, the user needs to copy and save it himself before selecting a reference in the policy.
The Javascript printed image library is copied from:https://www.fmz.com/strategy/27293Python's printed line class library copy address:https://www.fmz.com/strategy/39066
Here are some examples:
function main() {
while (true) {
var ticker = exchange.GetTicker()
if (ticker) {
$.PlotLine('Last', ticker.Last) //可以同时画两条线,Last是这条线的名字
$.PlotLine('Buy', ticker.Buy)
}
Sleep(6000)
}
}
The policy parameter setting below the policy editor, which is the global variable of the policy, can be accessed at any location in the code. The policy parameter can be modified in the real disk interface, which takes effect after restarting.
String types and numeric types are easy to understand and are the most commonly used types. The drop-down box will display optional drop-downs in the parameter interface, such as setting the drop-down box SYMBOL parameter value toBTC|USDT|ETH
If USDT is selected in the drop-down of the Parameters page, the value of the SYMBOL in the policy is index 1 for USDT. The check box is an optional box, ticked to true or false.
There are many parameters that can be set.https://www.fmz.com/bbs-topic/1306
Once a strategy has been quantified, you can test your strategy with historical data to see how your strategy performs in the historical data. Of course, the retest results are for reference only. The FMZ quantification platform supports retests of digital currency spot, futures, BitMEX futures, and futures, of which digital currency mainly supports mainstream varieties. Javascript retargeting is performed in the browser, Python retargeting needs to be on the host, which can be used to provide a public hosted platform. More parameters need to be set, specifically refer to the Mac language documentation.
The onbar retracement mechanism is based on a K-line, where each K-line generates a retracement time point at which information can be obtained about the current K-line's highs and lows, trading volume, etc., and before this time point.
gaoencheer api
ScienceHow do I implement the policy locally? I wrote a simple Log output statement and followed the end-of-sentence operation. The first step is to use a laptop as a server and run the host program. The second step is to write a simple test.py program for log output information (the FMZ API interface function); The third step, as at the end of the text, is to write a runfile and run it through run.py calling test.py. /upload/asset/1add39483ef82d45b3ce3.png
gyp9I bought the NetEase Cloud Quantitative Trading course, now where to go?
MonuRajak many
MonuRajak hi
I'm not sure.Learning
wqyThere's a small typo, GetAccount gets the account. In the introduction, FrozenStocks is supposed to be a frozen balance, not a available balance.
Lieutenant Jaya.getorder outtime get order outtime, exchange of okx, what to do
The Tree of LifeIf the collateral rate is not available, the collateral rate to 0% will be forced to break even.
shifeng2020I'm looking at a 1-minute k-string operation, so the sleep time of the Python dead loop can be set to 0.1s, which is sleep ((100)
East Windmillsexchange.SetDirection (("closebuy"); // if it is a permanent contract, directly set exchange.SetDirection (("sell") I tried OKex's perpetual contract here, and if it's set to sell, it's just empty, not cheap.
East Windmillsexchange.SetDirection (("closebuy"); // if it is a permanent contract, directly set exchange.SetDirection (("sell") I tried OKex's perpetual contract here, and if it's set to sell, it's just empty, not cheap.
East WindmillsThere are two spelling errors in the GetOrders code. One is that function is written as a function and the other is that it is written as a condition of the for loop.
East WindmillsIt was my fault. exchange.Buy ((-1, 0.5), the trading pair is ETH_BTC, the market price list represents the purchase of ETH for 0.5BTC exchange.Buy ((price, 0.5), if this is the limit list, it represents buying 0.5ETH at the price of the price
East Windmillsexchange.Buy ((-1, 0.5), the trading pair is ETH_BTC, which represents the market price of buying ETH of 0.5BTC This is supposed to be the market price for buying 0.5 ETH of nickel.
gyp9Thank you.
The grassIt has been on the web https://study.163.com/course/courseMain.htm?share=2&shareId=400000000602076&courseId=1006074239&_trace_c_p_k2_=c3f5d238efc3457d93c8b92c0398d2b2
The grassWeight Watchers adds a homepage to your group.
wqyI'm having trouble asking if we have an official chat group. Sometimes I don't know where to ask questions.
The grassChanged
The grassAcquire again
The grassYou can use GetRawJSON or view the info in the field
East WindmillsI found a lot of spelling mistakes in the code, haha.
The grassHi, corrected, thank you for pointing out the error.
The grassSome perpetual contracts allow bidirectional holdings, which need to be set to break even.