Sumber daya yang dimuat... Pemuatan...

Instruksi API FMZ

Penulis:Tidak ada, Dibuat: 2020-04-20 10:19:00, Diperbarui: 2023-04-12 14:44:56

alamat IP sted adalah10.0.3.15 }


#### exchange.SetTimeout(...)

```exchange.SetTimeout(Millisecond)```, in which the parameter **Millisecond** is a millisecond value.

Only for the ```rest``` protocol, it is used to set the time-out period for ```rest``` requests, and it takes effect only by setting it once.
For example: ```exchange.SetTimeout(3000)```, set the timeout time of the ```rest``` request of the exchange object ```exchange```, if it exceeds 3 seconds, timeout will return ```null```.

Note:
* The parameter ```Millisecond``` is millisecond, and 1,000 milliseconds equals 1 second. 
* Only need to set once.
* Only for the **rest** protocol.
* ```SetTimeout``` is not a global function, but an exchange object method. 

### Special Requirements for C++ Written Strategies   
The main difference between ```C++``` written strategy and ```JavaScript``` written strategy is the returned data differences of **FMZ API** interface. For example, the ```exchange.GetTicker()``` function.

- JavaScript
```exchange.GetTicker()``` returns an object if the call succeeds, or returns ```null``` if the call fails (due to the exchange server problems or network problems, etc.).

```javascript
function main() {
    var ticker = exchange.GetTicker()
    // Determine if the call to "exchange.GetTicker" function failed, and return "null" when it failed
    if (ticker){
        Log(ticker)
    }
}
  • C++exchange.GetTicker()mengembalikan objek, ketika panggilan berhasil. Jika panggilan gagal, objek yang dikembalikan masih merupakan objek, yang dibedakan dari objek yang dikembalikan normal oleh atributValid.

    void main() {
        auto ticker = exchange.GetTicker();
        // Determine if the call to "exchange.GetTicker()" function failed and if the "Valid" attribute of the returned object is "false"
        if (ticker.Valid) {
            Log(ticker);
        }
    }
    

Perbedaan antaramain()Fungsi dalamC++strategi tertulis danmain()fungsi dalam standar C11: Nilai pengembalianC++fungsi entri programmain()dalam C11 adalahintjenis.C++menulis strategi di platform FMZ, fungsi startup dari strategi juga fungsimain(), tapi keduanya bukan fungsi yang sama, hanya dengan nama yang sama.main()Fungsi dalamC++strategi adalah darivoid type.

void main() {
    // Use "Test" function to test
    if (!Test("c++")) {
        // Show an exception to stop the program
        Panic("Please download the latest-versioned docker");
    }

    // Determine if the return of all objects is valid with "Valid" 
    LogProfitReset();
    LogReset();
    Log(_N(9.12345, 2));
    Log("use _C", _C(exchange.GetTicker), _C(exchange.GetAccount));
}

Hal-hal khusus JavaScript

Untuk alasan bahasa JavaScript (JavaScript bahasa built-in mendukung stringasciidanutf-16mengkodekan hanya, untuk tidak kehilangan data), ketika ia menemukan string yang tidak dapat dienkode, itu akan mengembalikanArrayBuffersemua antarmuka API yang dapat melewati string parameter juga mendukung melewatiArrayBuffer type.

JavaScript multi-threading

Ini benar-benar mendukung fungsi multi-threading dariJavaScriptstrategi bahasa dari bagian bawah sistem, termasuk: eksekusi serentak fungsi eksekusi kustom; dukungan untuk komunikasi antara thread serentak, dukungan untuk komunikasi antara thread serentak dan thread utama; penyimpanan, berbagi variabel di lingkungan thread dan fungsi lainnya.https://www.fmz.com/bbs-topic/9974.

__Thread

Peraturan__Thread(function, arguments...)fungsi membuat thread yang berjalan secara bersamaan. Tidak mendukung referensi langsung ke variabel selain fungsi eksekusi thread (berjalan sebagai lingkungan yang terisolasi). Referensi ke variabel eksternal tidak akan berhasil dikompilasi. Referensi ke fungsi penutupan lainnya juga tidak didukung. Semua API platform dapat dipanggil di dalam thread, tetapi fungsi yang didefinisikan pengguna lainnya tidak dapat dipanggil. Parameterfunctiondapat menjadi referensi fungsi atau fungsi anonim.argumentsadalah parameter darifunctionfungsi (parameter yang sebenarnya dikirimkan), danarguments...berarti bahwa beberapa parameter dapat diteruskan kembali nilai: ID thread.

function testFunc(n) {
    Log("Execute the function testFunc, parameter n:", n)
}

function main() {
    var testThread1 = __Thread(function () {
        Log("Executes an anonymous function with no parameters.")
    })

    var testThread2 = __Thread(testFunc, 10)   // parameter n : 10
    
    __threadJoin(testThread1)                  // You can use the __threadJoin function to wait for concurrent threads to complete
    __threadJoin(testThread2)                  // If you don't wait for the execution of testThread1 and testThread2 to complete, the main thread will automatically release the concurrent thread after the execution is completed first, and terminate the execution function of the concurrent thread
}

Ini mendukung metode panggilan dari__Thread([function, arguments...], [function, arguments...], ...), yaitu, beberapa fungsi eksekusi thread dijalankan secara berurutan dalam thread yang dibuat.

function threadTestFuncA(a) {
    Log(a)
    threadTestFuncC(4)
    
    // The threadTestFuncC function can be called, but the threadTestFuncB function cannot be called

    // this.d
    Log(d)
}

function threadTestFuncB(b) {
    Log(b)
    threadTestFuncC(2)

    this.d = 5
}

function main() {
    // Execute the threadTestFuncB function first, and then execute the threadTestFuncA function
    // threadTestFuncC will not be executed automatically, but it can be called by other thread execution functions
    var threadId = __Thread([threadTestFuncA, 3], [threadTestFuncB, 1], ["function threadTestFuncC(c) {Log(c)}"])
    __threadJoin(threadId)
}

Fungsi eksekusi bersamaan diteruskan ke__Threadfungsi akan dijalankan dalam urutan terbalik. contoh di atas akan menggunakanLogfungsi untuk mencetak1 ~ 5Variabel bersama di antara fungsi eksekusi thread yang berbeda didukung.this.dvariabel dalam contoh di atas dapat ditugaskan dalamthreadTestFuncBfungsi dan digunakan dalamthreadTestFuncAFungsi. Ini mendukung lulus dalam string fungsi, seperti"function threadTestFuncC(c) {Log(c)}"dalam contoh di atas, yang memungkinkan thread untuk menjalankan panggilan fungsi ke fungsi eksternal dan perpustakaan diimpor dengan metode ini.

Untuk mengimpor perpustakaan eksternal, contoh penggunaan spesifik adalah sebagai berikut:

function ml(input) {
    const net = new brain.NeuralNetwork();
    net.train([
        { input: [0, 0], output: [0] },
        { input: [0, 1], output: [1] },
        { input: [1, 0], output: [1] },
        { input: [1, 1], output: [0] },
    ]);
    return net.run(input);
}

function main() {
    Log(__threadJoin(__Thread([ml, [1, 0]], [HttpQuery("https://unpkg.com/brain.js")])))
}

__threadPeekMessage

Peraturan__threadPeekMessage(threadId, timeout)fungsi membaca data dari saluran komunikasi thread, parameterthreadIdadalah Id yang dikembalikan oleh__Thread()fungsi, pengaturan parameterthreadIdberarti menerima data yang dikirim oleh thread yang diwakili oleh threadId. Ketika ditetapkan menjadi 0, itu berarti menerima data yang dikirim oleh thread utama, yaitu fungsi utama saat ini (parameter threadId ditetapkan menjadi 0, yang hanya didukung dalam fungsi eksekusi thread bersamaan). Parametertimeoutadalah pengaturan timeout, yang akan memblokir dan menunggu sesuai dengan jumlah milidetik yang ditetapkan oleh parameter ini.timeoutdiatur untuk-1, berarti untuk memblokir dan menunggu sampai data di saluran diterima.__threadPeekMessagefungsi akan mengembalikan nilai nol segera. Nilai kembali: data yang diterima.

Ketika menulis program, Anda perlu memperhatikan masalah thread deadlock. contoh berikut adalah komunikasi antara fungsi eksekusitestFuncdari benang paralel yang dibuat danmainfungsi benang utama, dan fungsi eksekusi benangtestFuncakan dieksekusi terlebih dahulu.

function testFunc() {
    for(var i = 0 ; i < 5 ; i++) {                // 0 ~ 5, after sending to the main thread 5 times, the execution of the thread function is completed, and the __threadPeekMessage function in the main function fetches all the data, it will not block again, and returns a null value immediately
        __threadPostMessage(0, i)                 // Send data to the main thread
        var msg = __threadPeekMessage(0, -1)      // Listen for data from the main thread
        Log("from main msg:", msg)
        Sleep(500)
    }
    Log("testFunc execution is complete")
}

function main() {
    var testThread = __Thread(testFunc)           // Create a thread with an Id of 1 
    
    for (var i = 0 ; i < 10 ; i++) {
        __threadPostMessage(1, i)                 // Send data to the thread whose Id is 1, that is, the thread that executes the testFunc function in this example
        var msg = __threadPeekMessage(1, -1)      // Listen to the data sent by the thread whose Id is 1, that is, the data sent by the thread that executes the testFunc function in the example
        Log("from testFunc msg:", msg)
        Sleep(500)
    }
}

__threadPostMessage

Peraturan__threadPostMessage(threadId, data)fungsi menulis data ke saluran komunikasi thread, parameterthreadIdadalah Id yang dikembalikan oleh__Thread()fungsi, mengatur parameterthreadIdberarti mengirim data ke thread yang diwakili oleh threadId, dan ketika ditetapkan menjadi 0, berarti mengirim data ke thread utama, yaitu fungsi utama saat ini (parameter threadId ditetapkan menjadi 0, yang hanya didukung dalam fungsi eksekusi thread bersamaan). Parameterdatadapat melewati nilai, string, nilai Boolean, objek, array dan jenis data lainnya.

Ketika__threadPostMessagefungsi dipanggil dalam fungsi eksekusi thread untuk mengirim sinyal dan data, sebuah acara pesan juga akan dihasilkan.EventLoop()fungsi untuk menerima pemberitahuan pesan.

function testFunc() {
    for(var i = 0 ; i < 10 ; i++) {
        Log("post msg, i:", i)
        __threadPostMessage(0, {msg: "testFunc", i: i})
        Sleep(100)
    }
}

function main() {
    var testThread = __Thread(testFunc)
    
    for (var i = 0 ; i < 10 ; i++) {
        var e = EventLoop()
        Log("e:", e)
        // e: {"Seq":1,"Event":"thread","Index":1,"Nano":1677745512064773600,"Deleted":0,"Symbol":"","Ticker":{"Info":null,"High":0,"Low":0,"Sell":0,"Buy":0,"Last":0,"Volume":0,"OpenInterest":0,"Time":0}}
        if (e.Event == "thread") {
            var msg = __threadPeekMessage(testThread, -1)
            Log("msg:", msg, "#FF0000")
        }
        Sleep(500)
    }
    
    var retThreadJoin = __threadJoin(testThread)
    Log("retThreadJoin:", retThreadJoin)
}

_threadBergabunglah

Peraturan__threadJoin(threadId, timeout)fungsi digunakan untuk menunggu thread dengan Id yang ditentukan untuk keluar dan merebut kembali sumber daya sistem.threadIdadalah Id yang dikembalikan oleh__Thread()fungsi, dan parametertimeoutadalah pengaturan timeout untuk menunggu akhir thread, dalam milidetik. Jika timeout tidak ditetapkan, itu berarti menunggu sampai akhir pelaksanaan thread. Nilai pengembalian: Tipe adalah objek, yang menunjukkan hasil pelaksanaan. Jika waktu habis, kembaliundefined.

Struktur nilai pengembalian, misalnya:

{
    "id":1,                 // Thread Id
    "terminated":false,     // Whether the thread is terminated forcibly
    "elapsed":2504742813,   // The running time of the thread (nanoseconds)
    "ret": 123              // The return value of the thread function
}

__threadTermine

Peraturan__threadTerminatefungsi digunakan untuk mengakhiri thread secara paksa dan melepaskan sumber daya perangkat keras yang digunakan oleh thread yang dibuat (the __threadJoin tidak dapat lagi digunakan untuk menunggu akhir). ParameterthreadIdadalah Id yang dikembalikan oleh__Thread()Nilai pengembalian: Nilai Boolean, yang menunjukkan hasil eksekusi.

function testFunc() {
    for(var i = 0 ; i < 10 ; i++) {
        Log("i:", i)
        Sleep(500)
    }
}

function main() {
    var testThread = __Thread(testFunc)
    
    var retThreadTerminate = null 
    for (var i = 0 ; i < 10 ; i++) {
        Log("main i:", i)
        if (i == 5) {
            retThreadTerminate = __threadTerminate(testThread)
        }
        Sleep(500)
    }
    
    Log("retThreadTerminate:", retThreadTerminate)
}

__threadGetData

__threadGetData(threadId, key), fungsi ini digunakan untuk mengakses variabel yang dibagikan di antara thread.__threadJoinfungsi (menunggu untuk exit yang sukses) dan belum melaksanakan__threadTerminatefungsi (mengakhiri benang secara paksa).threadIdadalah ID thread, dan parameterkeyadalah nama kunci yang disimpankey-valuenilai kembali: Mengembalikan nilai kunci yang sesuai dengankeydalamkey-value pair.

threadIdadalah 0 untuk menunjukkan benang utama (yaitu benang di manamainfungsi yang terletak), Anda dapat menggunakan__threadId()fungsi untuk mendapatkan Id dari thread saat ini, mengatur parameterthreadIdAnda juga dapat membaca variabel di lingkungan thread dari ID yang ditentukan.

function main() {
    var t1 = __Thread(function() {
        Sleep(2000)
        var id = __threadId()                                                   // Get the Id of the current thread
        Log("id:", id, ", in testThread1 print:", __threadGetData(id, "msg"))   // Retrieve the key value corresponding to the key name msg in the current thread, i.e. "testThread2"
        Log("id:", 2, ", in testThread1 print:", __threadGetData(2, "msg"))     // Read the key value corresponding to the key name msg in the thread with thread Id 2, i.e. 99
    })

    var t2 = __Thread(function(t) {
        __threadSetData(t, "msg", "testThread2")                                // Set a key-value pair to the thread with Id t1 (Id 1), with the key name msg and the key value "testThread2"
        __threadSetData(__threadId(), "msg", 99)                                // Set the key-value pair in the current thread (Id is 2) with the key name msg and the key value 99
        __threadSetData(0, "msg", 100)                                          // Set up a key-value pair in the main thread, with the key name msg and the key value 100
    }, t1)
    
    __threadJoin(t1)   // You can check the __threadJoin(threadId, timeout) function, which is used to wait for the end of thread execution
    Log("in main, get msg:", __threadGetData(0, "msg"))
}

__threadSetData

__threadSetData(threadId, key, value), yang digunakan untuk menyimpan variabel di lingkungan thread.threadIdadalah ID thread, parameterkeyadalah nama kunci yang disimpankey-valuepasangan, dan parametervalueadalah nilai kunci. Fungsi tidak memiliki nilai kembali.

threadIdadalah 0 untuk menunjukkan benang utama (yaitu benang di manamainfungsi yang terletak), dan Anda dapat menggunakan__threadId()fungsi untuk mendapatkan ID dari thread saat ini.valuetidak ditentukan cara untuk menghapuskey. Ini mendukung akses bersama ke variabel bersama antara thread. Data yang valid ketika thread belum melaksanakan__threadJoinfungsi (menunggu untuk exit berhasil) dan belum melaksanakan__threadTerminatefungsi (mengakhiri thread secara paksa). Nilai parametervalueharus menjadi variabel yang dapat diserialisasikan.

function testFunc() {
    var id = __threadId()                  // Get the current thread Id
    __threadSetData(id, "testFunc", 100)   // Stored in the current thread environment
    __threadSetData(0, "testFunc", 99)     // Stored in the main threaded environment
    Log("testFunc execution is complete")
}

function main() {
    // threadId is 1, the created thread with threadId 1 will be executed first, as long as the thread resources are not recycled, the variables stored locally in the thread will be valid
    var testThread = __Thread(testFunc)
    
    Sleep(1000)

    // Output in main, get testFunc: 100
    Log("in main, get testFunc:", __threadGetData(testThread, "testFunc"))

    // Output in main, get testFunc: 99
    Log("in main, get testFunc:", __threadGetData(0, "testFunc"))

    // Delete the testFunc key-value pair in the thread environment with Id testThread
    __threadSetData(testThread, "testFunc")

    // After deleting and reading again, the __threadGetData function returns undefined
    Log("in main, get testFunc:", __threadGetData(testThread, "testFunc"))
}

_threadId

__threadId(), yang digunakan untuk mendapatkan Id dari thread saat ini, tanpa parameter.threadIddari benang saat ini.

function testFunc() {
    Log("in testFunc, __threadId():", __threadId())
}

function main() {
    __Thread(testFunc)

    // If the execution of the main thread is completed, the created child thread will stop executing, so here Sleep(1000), wait for 1 second
    Sleep(1000)
    Log("in main, __threadId():", __threadId())
}

Dukungan coding wasm

DalamJavaScriptstrategi bahasa, kode hex dari file wasm dapat dimuat, instan, dan kode di dalamnya dijalankan.JavaScriptkode, itu memiliki keuntungan kecepatan tertentu.

wasm.parseModule

wasm.parseModule(data), yang menganalisis model string hex.dataparameter adalah pengkodean wasm yang telah dikonversi ke dalam string hex. Nilai kembali: Kembali objek model wasm, Anda dapat merujuk keContoh Strategi.

Misalnya, kode fungsi c ++ berikut dapat dikompilasi menjadi kode wasm, dan kemudian dikonversi menjadi string hex, yang dapat digunakan sebagaidataparameter dariwasm.parseModule(data) function.

// Recursive Algorithm for Fibonacci Numbers
int fib(int f) {
    if (f < 2) return f;
    return fib(f - 1) + fib(f - 2);   
}

wasm.buildInstance

wasm.buildInstance(module, opt), yang menciptakan contoh model wasm.moduleparameter adalah model wasm, danoptparameter adalah informasi konfigurasi, yang digunakan untuk mengatur ruang tumpukan yang dialokasikan untuk program instance wasm.

optcontoh pengaturan parameter:

{
    stack_size: 65*1024*1024,
}

callFunction

callFunction(funcName, param1, ...), yang merupakan metode dari contoh model wasm, digunakan untuk menjalankan fungsi dalam contoh model wasm.funcNameparameter adalah nama fungsi yang akan dijalankan, danparam1Parameter adalah parameter yang diteruskan saat menjalankan fungsi (ditentukan oleh parameterfuncName).

Blockchain

Platform FMZ Quant Trading secara resmi dapat diakses untuk mendukung panggilan interaktifweb3kontrak pada rantai, yang dapat mengaksesdefiBertukar dengan mudah.

Ethereum

Konfigurasi

Pada platform FMZ Quant Trading, tulis kode strategi untuk menerapkan panggilan metode kontrak pintar pada rantai Ethereum melaluiexchange.IOfungsi. Pertama, konfigurasi node akses pada platform FMZ Quant Trading. Node akses dapat menjadi node yang dibangun sendiri atau menggunakan layanan pihak ketiga, sepertiinfura.

Di halaman Bertukar FMZ Quant Trading platform, pilih protokol: cryptocurrency, dan kemudian memilih pertukaranWeb3. MengkonfigurasiRpc Address(alamat layanan node akses) danPrivate Key(kunci pribadi). Ini mendukung penyebaran lokal kunci pribadi, lihatKunci Keamanan].

Daftarkan ABI

Menelpon kontrak yang merupakan standarERC20metode tidak memerlukan pendaftaran dan dapat dipanggil secara langsung. Meminta metode selain kontrak standar membutuhkan pendaftaran konten ABI:exchange.IO("abi", tokenAddress, abiContent)Untuk mendapatkan konten ABI dari kontrak, Anda dapat menggunakan URL berikut untuk mendapatkannya, mengambil lapangan hasil saja.

https://api.etherscan.io/api?module=contract&action=getabi&address=0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45

Metode memanggil Ethereum RPC

Ketika parameter kedua dariexchange.IOfungsi adalah"eth", Anda dapat memanggil metode RPC yang tersedia untuk node server langsung, misalnya:

  • Menanyakan saldo ETH di dompet

    function main() {
        // "owner" needs to be replaced with a specific wallet address
        // "latest" parameter labels for string position: 'latest', 'earliest' or 'pending', please refer to https://eth.wiki/json-rpc/API#the-default-block-parameter
        // The return value ethBalance is a hexadecimal string: 0x9b19ce56113070
        var ethBalance = exchange.IO("api", "eth", "eth_getBalance", "owner", "latest")
    
        // ETH has a precision unit of 1e18
        var ethDecimal = 18
    
        // Because of the JavaScript language precision, it is necessary to use the system underlying encapsulated function BigInt, BigDecimal to process.
        // Convert ethBalance to readable quantity, 0x9b19ce56113070 to 0.043656995388076145.
        Log(Number((BigDecimal(BigInt(ethBalance))/BigDecimal(Math.pow(10, ethDecimal))).toString()))
    }
    
  • Transfer ETH

    function mian() {
        // ETH has a precision unit of 1e18
        var ethDecimal = 18
    
        // Number of transfers, readable quantity e.g. 0.01 ETH
        var sendAmount = 0.01
    
        // Because of the JavaScript language precision, it is necessary to use the system underlying encapsulated function BigInt, BigDecimal to process, and converts readable quantities into data for processing on the chain.
        var toAmount = (BigDecimal(sendAmount)*BigDecimal(Math.pow(10, ethDecimal))).toFixed(0)
        
        // "toAddress" is the address of the recipient's ETH wallet at the time of the transfer, which needs to be filled in specifically, and toAmount is the number of transfers.
        exchange.IO("api", "eth", "send", "toAddress", toAmount)
    }
    
  • Pertanyaan gasPrice

    function toAmount(s, decimals) {
        return Number((BigDecimal(BigInt(s))/BigDecimal(Math.pow(10, decimals))).toString())
    }  
    
    function main() {
        var gasPrice = exchange.IO("api", "eth", "eth_gasPrice")
        Log("gasPrice:", toAmount(gasPrice, 0))   // 5000000000 , in wei (5 gwei)
    }
    
  • Pertanyaan eth_estimateGas

    function toAmount(s, decimals) {
        // The toAmount function can convert the hex-encoded value to a decimal value
        return Number((BigDecimal(BigInt(s))/BigDecimal(Math.pow(10, decimals))).toString())
    }  
    
    function main() {
        // Encoding the call to the approve method
        var data = exchange.IO("encode", "0x111111111117dC0aa78b770fA6A738034120C302", "approve", "0xe592427a0aece92de3edee1f18e0157c05861564", "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")
        Log("data:", data)
        var gasPrice = exchange.IO("api", "eth", "eth_gasPrice")
        Log("gasPrice:", toAmount(gasPrice, 0))
        var obj = {
            "from" : "0x0xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",   // walletAddress
            "to"  : "0x111111111117dC0aa78b770fA6A738034120C302",
            "gasPrice" : gasPrice,
            "value" : "0x0",
            "data" : "0x" + data,
        }
        
        var gasLimit = exchange.IO("api", "eth", "eth_estimateGas", obj)
        Log("gasLimit:", toAmount(gasLimit, 0))
        Log("gas fee", toAmount(gasLimit, 0) * toAmount(gasPrice, 0) / 1e18)
    }
    

Dukungan untuk pengkodean

Fungsiexchange.IOmengkapsulkanencodemetode, yang dapat mengembalikan fungsi panggilan pengkodean untukhexAnda dapat merujuk ke platform yang tersedia untuk umumUniswap V3 Trading Class Library templateuntuk penggunaan khusus. Panggilan dari pengkodeanunwrapWETH9metode digunakan di sini sebagai contoh:

function main() {
    // Main network address of ContractV3SwapRouterV2: 0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45
    // To call the unwrapWETH9 method, you need to register the ABI first, omit the registration here.
    // "owner" represents the wallet address, it needs to fill in the specific, 1 represents the number of unwrapping, unwrap a WETH into ETH
    var data = exchange.IO("encode", "0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45", "unwrapWETH9(uint256,address)", 1, "owner")
    Log(data)
}

Saat meneleponexchange.IO("encode",...)fungsi, jika parameter kedua (tipe string) dimulai dengan0x, berarti panggilan metode pada kode (encodeJika tidak dimulai dengan0x, digunakan untuk mengkode urutan jenis yang ditentukan.abi.encodedalamsolidity. merujuk pada contoh berikut.

function main() {
    var x = 10 
    var address = "0x02a5fBb259d20A3Ad2Fdf9CCADeF86F6C1c1Ccc9"
    var str = "Hello World"
    var array = [1, 2, 3]
    var ret = exchange.IO("encode", "uint256,address,string,uint256[]", x, address, str, array)   // uint i.e. uint256 , the type length needs to be specified on FMZ
    Log("ret:", ret)
    /*
    000000000000000000000000000000000000000000000000000000000000000a    // x
    00000000000000000000000002a5fbb259d20a3ad2fdf9ccadef86f6c1c1ccc9    // address
    0000000000000000000000000000000000000000000000000000000000000080    // offset of str
    00000000000000000000000000000000000000000000000000000000000000c0    // offset of array
    000000000000000000000000000000000000000000000000000000000000000b    // the length of str
    48656c6c6f20576f726c64000000000000000000000000000000000000000000    // str data
    0000000000000000000000000000000000000000000000000000000000000003    // the length of the array
    0000000000000000000000000000000000000000000000000000000000000001    // array the first data
    0000000000000000000000000000000000000000000000000000000000000002    // array the second data
    0000000000000000000000000000000000000000000000000000000000000003    // array the third data
    */
}

Mendukung pengkodean berurutan dari tuples atau tipe yang mengandung tuples:

function main() {
    var types = "tuple(a uint256,b uint8,c address),bytes"
    var ret = exchange.IO("encode", types, {
        a: 30,
        b: 20,
        c: "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"
    }, "0011")
    Log("encode: ", ret)
}

Urutan jenis ini terdiri dari:tupledanbytes, jadi dua parameter harus diteruskan saat memanggilexchange.IOuntukencode:

    1. Variabel yang sesuai dengan tipetuple:
    {
        a: 30,
        b: 20,
        c: "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"
    }
    

    Parameter yang diberikan juga harus konsisten dengan struktur dan jenistuple, sebagaimana didefinisikan dalamtypesParameter:tuple(a uint256, b uint8, c address).

    1. Variabel yang sesuai dengan tipebytes:
    "0011"
    

Dukungan untuk pengkodean berurutan array atau tipe yang berisi array:

function main() {
    var path = ["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", "0xdac17f958d2ee523a2206206994597c13d831ec7"]   // ETH address, USDT address
    var ret = exchange.IO("encode", "address[]", path)
    Log("encode: ", ret)
}

Dukungan untuk encodePacked

Misalnya, ketika memanggil metode DEX dariUniswap V3, Anda perlu untuk lulus dalam parameter, seperti jalur pertukaran, sehingga Anda perlu menggunakanencodePackagedOperasi:

function main() {
    var fee = exchange.IO("encodePacked", "uint24", 3000)
    var tokenInAddress = "0x111111111117dC0aa78b770fA6A738034120C302"
    var tokenOutAddress = "0x6b175474e89094c44da98b954eedeac495271d0f"
    var path = tokenInAddress.slice(2).toLowerCase()
    path += fee + tokenOutAddress.slice(2).toLowerCase()
    Log("path:", path)
}

Dukungan untuk dekode

Pengolahan data tidak hanya mendukung pengkodean (encode), tetapi juga mendekode (decode) Menggunakanexchange.IO("decode", types, rawData)fungsi untuk melakukandecode operation.

function main() {
    // register SwapRouter02 abi
    var walletAddress = "0x398a93ca23CBdd2642a07445bCD2b8435e0a373f"
    var routerAddress = "0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45"
    var abi = `[{"inputs":[{"components":[{"internalType":"bytes","name":"path","type":"bytes"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"amountInMaximum","type":"uint256"}],"internalType":"struct IV3SwapRouter.ExactOutputParams","name":"params","type":"tuple"}],"name":"exactOutput","outputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"}],"stateMutability":"payable","type":"function"}]`
    exchange.IO("abi", routerAddress, abi)   // abi only uses the contents of the local exactOutput method, the full abi can be searched on the Internet

    // encode path
    var fee = exchange.IO("encodePacked", "uint24", 3000)
    var tokenInAddress = "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"
    var tokenOutAddress = "0xdac17f958d2ee523a2206206994597c13d831ec7"
    var path = tokenInAddress.slice(2).toLowerCase()
    path += fee + tokenOutAddress.slice(2).toLowerCase()
    Log("path:", path)

    var dataTuple = {
        "path" : path, 
        "recipient" : walletAddress, 
        "amountOut" : 1000, 
        "amountInMaximum" : 1, 
    }
    // encode SwapRouter02 exactOutput 
    var rawData = exchange.IO("encode", routerAddress, "exactOutput", dataTuple)
    Log("method hash:", rawData.slice(0, 8))   // 09b81346
    Log("params hash:", rawData.slice(8))

    // decode exactOutput params
    var decodeRaw = exchange.IO("decode", "tuple(path bytes,recipient address,amountOut uint256,amountInMaximum uint256)", rawData.slice(8))
    Log("decodeRaw:", decodeRaw)
}

Contoh ini melakukanencodePackedoperasi pertama selamapathproses parameter, karenaexactOutputpanggilan metode yang perlu dikodekan kemudian membutuhkanpathKemudian, parameterencodemetode dariexactOutputkontrak routing hanya memiliki satu parameter, dan jenis parameter adalahtuple. MetodeexactOutputnama dikodekan sebagai0x09b81346, yang didekode hasildecodeRawolehexchange.IO ("decode",...)metode, dan konsisten dengan variabeldataTuple.

Dukungan untuk beralih kunci pribadi

Ini mendukung beralih kunci pribadi untuk mengoperasikan beberapa alamat dompet, misalnya:

function main() {
    exchange.IO("key", "Private Key")   // "Private Key" represents the private key string, which needs to be filled in specifically
}

Metode panggilan kontrak pintar

Parameter pertama dariexchange.IOFungsi adalah:"api"menunjukkan bahwa panggilan ini adalah panggilan ekstensi.exchange.IOfungsi adalah alamat kontrak pintar yang akan dipanggil.

Jika metode yang dipanggil memilikipayableAnda perlu menambahkan transfer ETH nilai setelah nama metode (parameter keempat dariexchange.IOfungsi), yang dapat berupa angka atau memberikan nilai dalam bentuk string, misalnyamulticallmetodeUniswap V3Konten berikut adalah contoh beberapa panggilan metode kontrak pintar:

  • angka desimal

    Peraturandecimalsmetode adalahconstantmetodeERC20yang tidak menghasilkangasKonsumsi, dan dapat menanyakan data presisi daritoken.decimalsNilai pengembalian: data presisitoken.

    function main(){
        var tokenAddress = "0x111111111117dC0aa78b770fA6A738034120C302"    // The contract address of the token, in the example the token is 1INCH
        Log(exchange.IO("api", tokenAddress, "decimals"))                  // Query, print 1INCH tokens with precision index of 18
    }
    
  • tunjangan

    Peraturanallowancemetode adalahconstantmetodeERC20yang tidak menghasilkangasKonsumsi, dan dapat menanyakan jumlah yang diizinkan daritokenuntuk alamat kontrak tertentu.allowancemetode perlu lulus dalam 2 parameter, yang pertama adalah alamat dompet, dan yang kedua adalah alamat otorisasi.token.

    function main(){
        // The contract address of the token, in the example the token is 1INCH
        var tokenAddress = "0x111111111117dC0aa78b770fA6A738034120C302"            
    
        // For example, the query yields 10000000000000000000000, divided by the precision unit of the token 1e18, the current exchange object bound to the wallet to the spender address authorized 1 1INCH.
        Log(exchange.IO("api", tokenAddress, "allowance", "owner", "spender"))   
    }
    

    owner: Alamat dompet diganti dengan string owner dalam contoh.spender: Alamat kontrak yang sah diganti dengan string spender dalam contoh. dalam penggunaan yang sebenarnya, Anda perlu mengisi alamat secara khusus, misalnya alamat dapatUniswap V3 router v1.

  • menyetujui

    Peraturanapprovemetode ini adalah non-constantmetodeERC20yang menghasilkangaskonsumsi, yang digunakan untuk mengizinkantokenOperasi yang dilakukan pada alamat kontrak tertentu.approvemetode harus lulus dalam 2 parameter, yang pertama adalah alamat yang akan diizinkan dan yang kedua adalah jumlah yang diizinkan.txid.

    function main(){
        // The contract address of the token, in the example the token is 1INCH
        var tokenAddress = "0x111111111117dC0aa78b770fA6A738034120C302"   
    
        // The hexadecimal string of the authorization amount: 0xde0b6b3a7640000 , the corresponding decimal string: 1e18 , 1e18 divided by the precision unit of the token, i.e. 1 token amount, so this refers to the authorization of one token.
        Log(exchange.IO("api", tokenAddress, "approve", "spender", "0xde0b6b3a7640000"))  
    }
    

    spender: Alamat kontrak yang sah, contohnya digantikan oleh string spender, penggunaan sebenarnya perlu mengisi alamat tertentu, misalnya dapatUniswap V3 router v1 address. 0xde0b6b3a7640000: Jumlah otorisasi, yang diwakili di sini dengan menggunakan string hexadecimal, sesuai dengan nilai desimal1e18, dibagi dengantokensatuan presisi dalam contoh (yaitu, 1e18), menghasilkan 1token authorized.

    Parameter ketiga dariexchange.IOfungsi dilewatkan nama metodeapprove, yang juga dapat ditulis dalam bentukmethodId, misalnya: 0x571ac8b0. Hal ini juga mungkin untuk menulis nama metode standar penuh, seperti approve(address,uint256) .

  • multi-panggilan

    Peraturanmulticallmetode adalah metode nonkonstan dariUniswap V3, yang akan menghasilkangasKonsumsi dan digunakan untuk bertukar token dalam berbagai cara.multicallmetode dapat memiliki beberapa metode untuk menyampaikan parameter. Anda dapat menanyakan ABI yang berisi metode untuk rincian. Anda perlu mendaftarkan ABI sebelum memanggil metode.txid.

    Untuk contoh spesifik darimulticallmetode panggilan, silakan merujuk pada publikUniswap V3 Trading Class Library templatedari platform kami.

    Pseudocode digunakan di sini untuk menggambarkan beberapa detail:

    exchange.IO("api", ContractV3SwapRouterV2, "multicall(uint256,bytes[])", value, deadline, data)
    

    ContractV3SwapRouterV2: alamat router v2 dari Uniswap V3.value: Jumlah ETH yang ditransfer, atur ke 0 jikatokenIntoken untuk operasi pertukaran bukanlah ETH.deadline: Bisa diatur ke(new Date().getTime() / 1000) + 3600, yang berarti itu berlaku selama satu jam.data: Data dari operasi pengemasan yang akan dilakukan.

    Hal ini juga mungkin untuk menentukangasLimit/gasPrice/noncesetting untuk panggilan metode, kita menggunakan pseudocode untuk menggambarkan lagi:

    exchange.IO("api", ContractV3SwapRouterV2, "multicall(uint256,bytes[])", value, deadline, data, {gasPrice: 123456, gasLimit: 21000})
    

    Anda dapat mengatur parameter{gasPrice: 11, gasLimit: 111, nonce: 111}sesuai dengan kebutuhan spesifik Anda, parameter diatur ke parameter terakhir dariexchange.IOAnda dapat menghilangkannoncedan menggunakan sistem default, atau tidak mengaturgasLimit/gasPrice/noncedan gunakan semua nilai default sistem.

    Perlu dicatat bahwa dalam contoh, atribut daristateMutabilitydalammulticall(uint256,bytes[])metode adalahpayable, danvalueAtribut daristateMutability":"payable"dapat dilihat dariABI.exchange.IOfungsi akan menentukan parameter yang diperlukan sesuai denganstateMutabilityatribut dalamABIyang telah terdaftar.stateMutabilityatribut adalahnonpayable, parametervaluetidak perlu diserahkan.

Panggilan fungsi umum

  1. Dapatkan alamat dompet yang dikonfigurasi oleh objek pertukaran.
function main() {
    Log(exchange.IO("address"))         // Print the wallet address of the private key configured on the exchange object.
}
  1. Ubah node blockchain RPC.
function main() {
    var chainRpc = "https://bsc-dataseed.binance.org"
    e.IO("base", chainRpc)    // Switch to BSC chain
}

Fungsi Indikator

Saat memanggil fungsi indikator, Anda perlu menambahkanTA.atautalib.sebagai awalan

Contoh panggilan fungsi indikator dalamtalibperpustakaan danTAperpustakaan:

function main(){
    var records = exchange.GetRecords()
    var macd = TA.MACD(records)
    var atr = TA.ATR(records, 14)

    // Print the last row of indicator values
    Log(macd[0][records.length-1], macd[1][records.length-1], macd[2][records.length-1])
    Log(atr[atr.length-1])

    // Print all indicator data, and JavaScript written strategies have integrated a talib library on FMZ Quant Trading platform 
    Log(talib.MACD(records))
    Log(talib.MACD(records, 12, 26, 9))
    Log(talib.OBV(records))

    // The talib library can also be passed in an array of numbers, which can be passed in order. For example: OBV (Records [Close], Records [Volume]) requires the parameters of the two arrays, including "Close" and "Volume"
    Log(talib.OBV([1,2,3], [7.1, 6.2, 3, 3]))

    // You can also directly pass in the "records" array containing the "Close" and "Volume" attribute
    Log(talib.OBV(records))
    Log(TA.Highest(records, 30, 'High'))
    Log(TA.Highest([1,2,3,4], 0))
}
# Python needs to install the talib library separately 
import talib
def main():
    r = exchange.GetRecords()
    macd = TA.MACD(r)
    atr = TA.ATR(r, 14)
    Log(macd[0][-1], macd[1][-1], macd[2][-1])
    Log(atr[-1])

    # For Python, the system extends the attributes of the array returned by GetRecords, and adds "Open", "High", "Low", "Close" and "Volume" to facilitate the call of the functions in the talib library
    Log(talib.MACD(r.Close))
    Log(talib.MACD(r.Close, 12, 26, 9))
    Log(talib.OBV(r.Close, r.Volume))

    Log(TA.Highest(r, 30, "High"))
    Log(TA.Highest([1, 2, 3, 4], 0))
void main() {
    auto r = exchange.GetRecords();
    auto macd = TA.MACD(r);
    auto atr = TA.ATR(r, 14);
    Log(macd[0][macd[0].size() - 1], macd[1][macd[1].size() - 1], macd[2][macd[2].size() - 1]);
    Log(atr[atr.size() - 1]);

    Log(talib.MACD(r));
    Log(talib.MACD(r, 12, 26, 9));
    Log(talib.OBV(r));

    Log(TA.Highest(r.Close(), 30));
}

Data dalam parameter berikut adalah semua data yang diperoleh oleh fungsiexchange.GetRecords(Period)Aku tidak tahu. Perhatikan panjangnyarecords, ketika panjang tidak memenuhi persyaratan perhitungan parameter dari fungsi indikator, nilai yang tidak valid akan dikembalikan.

TA - Perpustakaan Indikator yang umum digunakan

PeraturanTAPerpustakaan indikator dari platform FMZ Quant Trading telah mengoptimalkan algoritma indikator yang umum digunakan untuk mendukung panggilan strategi yang ditulis dalamJavaScript, Pythondancpp Kode perpustakaan TA sumber terbuka.

MACD - Rata-rata Bergerak Konvergensi & Divergensi

TA.MACD(data, fast period, slow period, signal period), dengan parameter periode default (12, 26, 9) mengembalikan array dua dimensi, yang[DIF, DEA, MACD] respectively.

function main(){
    // You can fill in different k-line periods, such as PERIOD_M1, PERIOD_M30 and PERIOD_H1...
    var records = exchange.GetRecords(PERIOD_M15)
    var macd = TA.MACD(records, 12, 26, 9)
    // You can see from the log that three arrays are returned, corresponding to DIF, DEA, MACD
    Log("DIF:", macd[0], "DEA:", macd[1], "MACD:", macd[2])
}
def main():
    r = exchange.GetRecords(PERIOD_M15)
    macd = TA.MACD(r, 12, 26, 9)
    Log("DIF:", macd[0], "DEA:", macd[1], "MACD:", macd[2])
void main() {
    auto r = exchange.GetRecords(PERIOD_M15);
    auto macd = TA.MACD(r, 12, 26, 9);
    Log("DIF:", macd[0], "DEA:", macd[1], "MACD:", macd[2]);
}

KDJ - Indikator Stokastik

TA.KDJ(data, period 1, period 2, period 3), dengan parameter periode default dari (9, 3, 3) mengembalikan array dua dimensi, yang(K, D, J) respectively.

function main(){
    var records = exchange.GetRecords(PERIOD_M15)
    var kdj = TA.KDJ(records, 9, 3, 3)
    Log("k:", kdj[0], "d:", kdj[1], "j:", kdj[2])
}
def main():
    r = exchange.GetRecords(PERIOD_M15)
    kdj = TA.KDJ(r, 9, 3, 3)
    Log("k:", kdj[0], "d:", kdj[1], "j:", kdj[2])
void main() {
    auto r = exchange.GetRecords();
    auto kdj = TA.KDJ(r, 9, 3, 3);
    Log("k:", kdj[0], "d:", kdj[1], "j:", kdj[2]);
}

RSI - Indeks Kekuatan Relatif

TA.RSI(data, period), dengan parameter periode default 14, mengembalikan array satu dimensi.

function main(){
    var records = exchange.GetRecords(PERIOD_M30)
    var rsi = TA.RSI(records, 14)
    Log(rsi)
}
def main():
    r = exchange.GetRecords(PERIOD_M30)
    rsi = TA.RSI(r, 14)
    Log(rsi)
void main() {
    auto r = exchange.GetRecords(PERIOD_M30);
    auto rsi = TA.RSI(r, 14);
    Log(rsi); 
}

ATR - Rata-rata Volatilitas Benar

TA.ATR(data, period); ATR ((data, periode), dengan parameter periode default 14, mengembalikan array satu dimensi.

function main(){
    var records = exchange.GetRecords(PERIOD_M30)
    var atr = TA.ATR(records, 14)
    Log(atr)
}
def main():
    r = exchange.GetRecords(PERIOD_M30)
    atr = TA.ATR(r, 14)
    Log(atr)
void main() {
    auto r = exchange.GetRecords(PERIOD_M30);
    auto atr = TA.ATR(r, 14);
    Log(atr);
}

OBV - Volume Saldo

TA.OBV(data)Mengembalikan array satu dimensi.

function main(){
    var records = exchange.GetRecords(PERIOD_M30)
    var obv = TA.OBV(records)
    Log(obv)
}
def main():
    r = exchange.GetRecords(PERIOD_M30)
    obv = TA.OBV(r)
    Log(obv)
void main() {
    auto r = exchange.GetRecords(PERIOD_M30);
    auto obv = TA.OBV(r);
    Log(obv);
}

MA - Rata-rata bergerak

TA.MA(data, period); MA ((data, periode), dengan parameter periode default 9, mengembalikan array satu dimensi.

function main(){
    var records = exchange.GetRecords(PERIOD_M30)
    var ma = TA.MA(records, 14)
    Log(ma)
}
def main():
    r = exchange.GetRecords(PERIOD_M30)
    ma = TA.MA(r, 14)
    Log(ma)
void main() {
    auto r = exchange.GetRecords(PERIOD_M30);
    auto ma = TA.MA(r, 14);
    Log(ma);
}

EMA - Rata-rata Gerak Eksponensial

TA.EMA(data, period)adalah indikator rata-rata eksponensial, dengan parameter periode default 9, mengembalikan array satu dimensi.

function main(){
    var records = exchange.GetRecords()
    // Determine if the number of K-line bars meets the requirement of the indicator calculation period 
    if (records && records.length > 9) {
        var ema = TA.EMA(records, 9)          
        Log(ema)
    }
}
def main():
    r = exchange.GetRecords()
    if r and len(r) > 9:
        ema = TA.EMA(r, 9)
        Log(ema)
void main() {
    auto r = exchange.GetRecords();
    if(r.Valid && r.size() > 9) {
        auto ema = TA.EMA(r, 9);
        Log(ema);
    }
}

BOLL - Bollinger Bands

TA.BOLL(data, period, multiplier); BOLL ((data, periode, multiplier) adalah indikator Bollinger Band, dengan parameter default (20, 2), dan mengembalikan array dua dimensi, yaitu[Upline, Midline, Downline].

function main() {
    var records = exchange.GetRecords()
    if(records && records.length > 20) {
        var boll = TA.BOLL(records, 20, 2)
        var upLine = boll[0]
        var midLine = boll[1]
        var downLine = boll[2]
        Log(upLine)
        Log(midLine)
        Log(downLine)
    }
}
def main():
    r = exchange.GetRecords()
    if r and len(r) > 20:
        boll = TA.BOLL(r, 20, 2)
        upLine = boll[0]
        midLine = boll[1]
        downLine = boll[2]
        Log(upLine)
        Log(midLine)
        Log(downLine)
void main() {
    auto r = exchange.GetRecords();
    if(r.Valid && r.size() > 20) {
        auto boll = TA.BOLL(r, 20, 2);
        auto upLine = boll[0];
        auto midLine = boll[1];
        auto downLine = boll[2];
        Log(upLine);
        Log(midLine);
        Log(downLine);
    }
}

Buaya - Indikator Buaya

TA.Alligator(data, mandible period, tooth period, upper lip period); Alligator ((data, periode rahang, periode gigi, periode bibir atas) adalah indikator Alligator, dengan parameter default (13,8,5), dan mengembalikan array dua dimensi, yaitu[Mandible, Teeth, Upper Lip].

CMF - Aliran uang Chaikin

TA.CMF(data, period); CMF ((data, periode) adalah indikator Aliran Uang Chaikin, dengan parameter periode default 20, mengembalikan array satu dimensi.

Harga tertinggi - periode tertinggi

TA.Highest(data, period, attribute), mengembalikan nilai maksimum dalam periode terbaru (tidak termasuk Bar saat ini), sepertiTA.Highest(records, 30, 'High'). Jikaperiodadalah 0, itu berarti semua Bars. Jikaattributetidak ditentukan, data dianggap sebagai array biasa, dan mengembalikan harga (jenis nilai).

Harga Terendah - Periode Harga Terendah

TA.Lowest(data, period, attribute), mengembalikan nilai minimum dalam periode terbaru (tidak termasuk Bar saat ini), sepertiTA.Highest(records, 30, 'Low'). JikaperiodJika atribut tidak ditentukan, data dianggap sebagai array biasa, dan harga (jenis nilai) dikembalikan.

PenggunaanTA.Highest(...)danTA.Lowest(...)dalamC++strategi harus dicatat bahwaHighestdanLowestfungsi hanya memiliki 2 parameter masing-masing, dan parameter pertama bukan nilai kembali dariauto r = exchange.GetRecords()fungsi, jadi Anda perlu memanggil metode dariruntuk menyampaikan data atribut tertentu, misalnya: passr.Close()Data harga penutupanClose, High, Low, Open, Volumeadalah sepertir.Close().

C++contoh:

void main() { 
    Records r;
    r.Valid = true;
    for (auto i = 0; i < 10; i++) {
        Record ele;
        ele.Time = i * 100000;
        ele.High = i * 10000;
        ele.Low = i * 1000;
        ele.Close = i * 100;
        ele.Open = i * 10;
        ele.Volume = i * 1;
        r.push_back(ele);
    }

    for(int j = 0; j < r.size(); j++){
        Log(r[j]);
    }

    // Note: if the first parameter passed in is not r, you need to call "r.Close()"
    auto highest = TA.Highest(r.Close(), 8);   
    Log(highest);                     
}

Perpustakaan Pihak Ketiga

JavaScript

C++

Contoh-contoh

  • JavaScriptperpustakaanhttp://mathjs.org/

    function main() {
        Log(math.round(math.e, 3))                // 2.718
        Log(math.atan2(3, -3) / math.pi)          // 0.75
        Log(math.log(10000, 10))                  // 4
        Log(math.sqrt(-4))                        // {"mathjs":"Complex","re":0,"im":2}   
    }
    

    http://mikemcl.github.io/decimal.js/

    function main() {
        var x = -1.2
        var a = Decimal.abs(x)
        var b = new Decimal(x).abs()
        Log(a.equals(b))                           // true  
    
        var y = 2.2
        var sum = Decimal.add(x, y)
        Log(sum.equals(new Decimal(x).plus(y)))

Lebih banyak