Use trading terminal plug-in to facilitate manual trading
Tags: trading, fmzquant, cryptocurrency, terminal
Published: 2024-05-31 06:29:11

## Introduction
FMZ.COM, as a quantitative trading platform, is mainly to serve programmatic traders. But it also provides a basic trading terminal. Although the function is simple, sometimes it can be useful. For example, if the exchange is busy and cannot be operated, but the API still works. At this time, you can withdraw orders, place orders, and view them through the terminal. In order to improve the experience of the trading terminal, plug-ins are now added. Sometimes, we need a small function to assist the transaction, such as ladder pending orders, iceberg orders, one-click hedging, one-click closing positions and other operations. It is not necessary to look at the execution log. It is a bit cumbersome to create a new robot. Just click the plugin in the terminal, the corresponding functions can be realized immediately, which can greatly facilitate manual transactions. The plug-in location is as follows:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/urd3g1jd9eyl27ltklzt.png)

## Plug-in principle
There are two modes of plug-in operation, immediate operation and background operation. Running in the background is equivalent to creating a robot (normal charges). The principle of immediate operation is the same as the debugging tool: send a piece of code to the docker of the trading terminal page for execution, and support to return charts and tables (the debugging tool is currently also upgraded to support), the same can only be executed for 5 minutes, no fees, no restrictions Language. Plug-ins with a short execution time can use immediate run mode, while complex and long-time running strategies still need to run robots.

When writing a strategy, you need to select the strategy type as a plug-in. The result of the main function return of the plug-in will be popped up in the terminal after the operation is over, supporting strings, drawing and tables. Because the plug-in execution cannot see the log, you can return the execution result of the plug-in.

## How to use
- Add strategy
Search directly in the search box as shown in the figure. Note that only trading plugin type strategies can be run, and then click Add. The public plug-ins can be found in Strategy Square: https://www.fmz.com/square/21/1

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cekor9lcvya7avxw8of6.png)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0yodql5d6xx716ivcwkd.png)

- Run the plugin
Click on the strategy to enter the parameter setting interface. If there are no parameters, it will run directly. The docker, trading pair, and K-line period selected by the trading terminal are the default corresponding parameters. Click the execution strategy to start execution, and select the "Execute Now" mode (you can remember the default operation mode). The plugin will not display the log.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/g2rtbez33wl2gwqw5d6g.png)

- Stop plugin
Click the icon position to stop the plug-in. Since all plug-ins are executed in a debugging tool process, all plug-ins will be stopped.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/k4deqtd1ih90dn7z8yhk.png)

## Examples of plug-in uses
Plug-ins can execute code for a period of time and perform some simple operations. In many cases, manual operations that require repeated operations can be implemented with plug-ins to facilitate transactions. The following will introduce specific examples, and the source code given can be used for reference to customize your own strategy.

## Assist manual futures intertemporal hedging trading
Futures intertemporal hedging trading is a very common strategy. Because the frequency is not very high, many people will manually operate it. It is necessary to make one contract long and one contract short, so it is better to analyze the spread trend. Using plug-ins in the trading terminal will save your energy.

The first introduction is to draw the inter-period price difference plugin:

```
var chart = { 
   __isStock: true,    
   title : { text : 'Spread analysis chart'},                     
   xAxis: { type: 'datetime'},                 
   yAxis : {                                        
       title: {text: 'Spread'},                   
       opposite: false,                             
   },
   series : [                    
       {name : "diff", data : []}, 

   ]
}
function main() {
   exchange.SetContractType('quarter')
   var recordsA = exchange.GetRecords(PERIOD_M5) //Cycle can be customized
   exchange.SetContractType('this_week')
   var recordsB = exchange.GetRecords(PERIOD_M5)
   
   for(var i=0;i<Math.min(recordsA.length,recordsB.length);i++){
       var diff = recordsA[recordsA.length-Math.min(recordsA.length,recordsB.length)+i].Close - recordsB[recordsB.length-Math.min(recordsA.length,recordsB.length)+i].Close
       chart.series[0].data.push([recordsA[recordsA.length-Math.min(recordsA.length,recordsB.length)+i].Time, diff])
   }
   return chart
}
```
Click once, the recent inter-period price difference is clear at a glance, the plug-in source code copy address: https://www.fmz.com/strategy/187755

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yjmxpo3tj98o7crjmlh4.png)

With the spread analysis, it is found that the spread is converging. It is an opportunity to short the quarterly contract and go long for the current week. This is an opportunity to use the one-click hedging plug-in, one click will automatically help you short the quarterly and long the weekly, which is faster than manual operation. The implementation principle of the strategy is to open the same number of positions with a sliding price. You can run several more times to slowly reach your desired position to avoid impacting the market. You can change the default parameters to place orders faster. Strategy copy address: https://www.fmz.com/strategy/191348

```
function main(){
    exchange.SetContractType(Reverse ? Contract_B : Contract_A)
    var ticker_A = exchange.GetTicker()
    if(!ticker_A){return 'Unable to get quotes'}
    exchange.SetDirection('buy')
    var id_A = exchange.Buy(ticker_A.Sell+Slip, Amount)
    exchange.SetContractType(Reverse ? Contract_B : Contract_A)
    var ticker_B = exchange.GetTicker()
    if(!ticker_B){return 'Unable to get quotes'}
    exchange.SetDirection('sell')
    var id_B = exchange.Sell(ticker_B.Buy-Slip, Amount)
    if(id_A){
        exchange.SetContractType(Reverse ? Contract_B : Contract_A)
        exchange.CancelOrder(id_A)
    }
    if(id_B){
        exchange.SetContractType(Reverse ? Contract_B : Contract_A)
        exchange.CancelOrder(id_B)
    }
    return 'Position: ' + JSON.stringify(exchange.GetPosition())
}
```
Waiting for the price difference to converge and you need to close the position, you can run the one-click closing plugin to close the position as quickly as possible.

```
function main(){
    while(ture){
        var pos = exchange.GetPosition()
        var ticker = exchange.GetTicekr()
        if(!ticker){return 'Unable to get ticker'}
        if(!pos || pos.length == 0 ){return 'No holding position'}
        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)
            }
        }
    }
}
```
## Plug-in to assist spot trading
The most common one is the iceberg commission, which splits large orders into small orders. Although it can be run as a robot, a 5-minute plug-in is actually sufficient. There are two types of iceberg orders, one is taking orders and the other is pending orders. If there is a preferential fee, you can choose pending orders, which means the execution time is longer.

The following code is the source code of the plug-in commissioned by iceberg: https://www.fmz.com/strategy/191771. For Selling: https://www.fmz.com/strategy/191772

```
function main(){
    var initAccount = _C(exchange.GetAccount)
    while(true){
        var account = _C(exchange.GetAccount)
        var dealAmount = account.Stocks - initAccount.Stocks
        var ticker = _C(exchange.GetTicker)
        if(BUYAMOUNT - dealAmount >= BUYSIZE){
            var id = exchange.Buy(ticker.Sell, BUYSIZE)
            Sleep(INTERVAL*1000)
            if(id){
                exchange.CancelOrder(id) // May cause error log when the order is completed, which is all right.
            }else{
                throw 'buy error'
            }
        }else{
            account = _C(exchange.GetAccount)
            var avgCost = (initAccount.Balance - account.Balance)/(account.Stocks - initAccount.Stocks)
            return 'Iceberg order to buy is done, avg cost is '+avgCost
        }
        
    }
}
```
It is also a way to slowly "ship products" to occupy Buying 1 or Selling 1 price layer all the time, and the impact on the market is relatively small. There are some improvements to this strategy. You can manually change the minimum transaction volume or accuracy.

Buy: https://www.fmz.com/strategy/191582

Sell: https://www.fmz.com/strategy/191730

```
function GetPrecision(){
    var precision = {price:0, amount:0}
    var depth = exchange.GetDepth()
    for(var i=0;i<exchange.GetDepth().Asks.length;i++){
        var amountPrecision = exchange.GetDepth().Asks[i].Amount.toString().indexOf('.') > -1 ? exchange.GetDepth().Asks[i].Amount.toString().split('.')[1].length : 0
        precision.amount = Math.max(precision.amount,amountPrecision)
        var pricePrecision = exchange.GetDepth().Asks[i].Price.toString().indexOf('.') > -1 ? exchange.GetDepth().Asks[i].Price.toString().split('.')[1].length : 0
        precision.price = Math.max(precision.price,pricePrecision)
    }
    return precision
}

function main(){
    var initAccount = exchange.GetAccount()
    if(!initAccount){return 'Unable to get account information'}
    var precision = GetPrecision()
    var buyPrice = 0
    var lastId = 0
    var done = false
    while(true){
        var account = _C(exchange.GetAccount)
        var dealAmount = account.Stocks - initAccount.Stocks
        var ticker = _C(exchange.GetTicker)
        if(BuyAmount - dealAmount > 1/Math.pow(10,precision.amount) && ticker.Buy > buyPrice){
            if(lastId){exchange.CancelOrder(lastId)}
            var id = exchange.Buy(ticker.Buy, _N(BuyAmount - dealAmount,precision.amount))
            if(id){
                lastId = id
            }else{
                done = true
            }
        }
        if(BuyAmount - dealAmount <= 1/Math.pow(10,precision.amount)){done = true}
        if(done){
            var avgCost = (initAccount.Balance - account.Balance)/dealAmount
            return 'order is done, avg cost is ' + avgCost  // including fee cost
        }
        Sleep(Intervel*1000)
    }
}
```
Sometimes, in order to sell a better "shipping price" or wait for a "missing" pending order, multiple orders can be placed at a certain interval. This plugin can also be used for futures pending orders. Source copy address: https://www.fmz.com/strategy/190017

```
function main() {
    var ticker = exchange.GetTicker()
    if(!ticker){
        return  'Unable to get price'
    }
    for(var i=0;i<N;i++){
        if(Type == 0){
            if(exchange.GetName().startsWith('Futures')){
                exchange.SetDirection('buy')
            }
            exchange.Buy(Start_Price-i*Spread,Amount+i*Amount_Step)
        }else if(Type == 1){
            if(exchange.GetName().startsWith('Futures')){
                exchange.SetDirection('sell')
            }
            exchange.Sell(Start_Price+i*Spread,Amount+i*Amount_Step)
        }else if(Type == 2){
            exchange.SetDirection('closesell')
            exchange.Buy(Start_Price-i*Spread,Amount+i*Amount_Step)
        }
        else if(Type == 3){
            exchange.SetDirection('closebuy')
            exchange.Sell(Start_Price+i*Spread,Amount+i*Amount_Step)
        }
        Sleep(500)
    }
    return 'order complete'
}
```
## Plug-in to assist commodity futures trading
Commonly used futures trading software often has many advanced pending order functions, such as pending stop-loss orders, pending condition orders, etc., which can be easily written as plug-ins. Here is a plugin for closing a pending order immediately after the pending order is traded. Copy address: https://www.fmz.com/strategy/187736

```
var buy = false
var trade_amount = 0
function main(){
    while(true){
        if(exchange.IO("status")){
            exchange.SetContractType(Contract)
            if(!buy){
                buy = true
                if(Direction == 0){
                    exchange.SetDirection('buy')
                    exchange.Buy(Open_Price, Amount)
                }else{
                    exchange.SetDirection('sell')
                    exchange.Sell(Open_Price, Amount)
                }
            }
            var pos = exchange.GetPosition()
            if(pos && pos.length > 0){
                for(var i=0;i<pos.length;i++){
                    if(pos[i].ContractType == Contract && pos[i].Type == Direction && pos[i].Amount-pos[i].FrozenAmount>0){
                        var cover_amount = math.min(Amount-trade_amount, pos[i].Amount-pos[i].FrozenAmount)
                        if(cover_amount >= 1){
                            trade_amount += cover_amount
                            if(Direction == 0){
                                exchange.SetDirection('closebuy_today')
                                exchange.Sell(Close_Price, cover_amount)
                            }else{
                                exchange.SetDirection('closesell_today')
                                exchange.Buy(Close_Price, cover_amount)
                            }
                        }
                    }
                }
            }
        } else {
            LogStatus(_D(), "CTP is not connected!")
            Sleep(10000)
        }
        if(trade_amount >= Amount){
            Log('mission completed')
            return
        }
        Sleep(1000)
    }
}
```
## To sum up
After reading so many small functions, you should also have your own ideas. You may wish to write a plug-in to facilitate your manual trading.

From: https://blog.mathquant.com/2020/07/30/use-trading-terminal-plug-in-to-facilitate-manual-trading.html