Cara Membedah Mesin Pemetik Cengkeh (1)

Penulis:Mimpi kecil, Dibuat: 2020-11-12 22:11:32, Diperbarui: 2023-09-26 21:04:43

img

Analisis strategi mesin pemanen celery

Perdebatan di komunitas WeChat terbaru tentang penemu kuantitatifprint moneyPada saat yang sama, beberapa orang yang tidak tahu apa-apa tentang robot, dan diskusi yang sangat hangat, membuat strategi yang sangat lama kembali masuk ke dalam pandangan orang-orang liberal:Mesin pemetik kedelaiprint moneyPada saat itu, ia merasa tidak terlalu mengerti tentang strategi mesin pemotong kedelai. Jadi, dia kembali serius melihat strategi asli dan melihat versi transplantasi yang diukur oleh penemu.Mempindahkan OKCoin ke mesin pemetik lobakAku tidak tahu. Dengan mengkuantifikasi strategi mesin pemotong kedelai versi platform, para penemu menguraikan strategi tersebut dan mengeksplorasi ide strategi tersebut. Dalam artikel ini, kita lebih banyak menganalisis dari sisi ide-ide strategis, niat, dan lain-lain, dan mencoba untuk mengurangi konten yang membosankan terkait pemrograman.

[Transplantasi OKCoin ke Mesin Pemetik Kelapa]

function LeeksReaper() {
    var self = {}
    self.numTick = 0
    self.lastTradeId = 0
    self.vol = 0
    self.askPrice = 0
    self.bidPrice = 0
    self.orderBook = {Asks:[], Bids:[]}
    self.prices = []
    self.tradeOrderId = 0
    self.p = 0.5
    self.account = null
    self.preCalc = 0
    self.preNet = 0

    self.updateTrades = function() {
        var trades = _C(exchange.GetTrades)
        if (self.prices.length == 0) {
            while (trades.length == 0) {
                trades = trades.concat(_C(exchange.GetTrades))
            }
            for (var i = 0; i < 15; i++) {
                self.prices[i] = trades[trades.length - 1].Price
            }
        }
        self.vol = 0.7 * self.vol + 0.3 * _.reduce(trades, function(mem, trade) {
            // Huobi not support trade.Id
            if ((trade.Id > self.lastTradeId) || (trade.Id == 0 && trade.Time > self.lastTradeId)) {
                self.lastTradeId = Math.max(trade.Id == 0 ? trade.Time : trade.Id, self.lastTradeId)
                mem += trade.Amount
            }
            return mem
        }, 0)

    }
    self.updateOrderBook = function() {
        var orderBook = _C(exchange.GetDepth)
        self.orderBook = orderBook
        if (orderBook.Bids.length < 3 || orderBook.Asks.length < 3) {
            return
        }
        self.bidPrice = orderBook.Bids[0].Price * 0.618 + orderBook.Asks[0].Price * 0.382 + 0.01
        self.askPrice = orderBook.Bids[0].Price * 0.382 + orderBook.Asks[0].Price * 0.618 - 0.01
        self.prices.shift()
        self.prices.push(_N((orderBook.Bids[0].Price + orderBook.Asks[0].Price) * 0.35 +
            (orderBook.Bids[1].Price + orderBook.Asks[1].Price) * 0.1 +
            (orderBook.Bids[2].Price + orderBook.Asks[2].Price) * 0.05))
    }
    self.balanceAccount = function() {
        var account = exchange.GetAccount()
        if (!account) {
            return
        }
        self.account = account
        var now = new Date().getTime()
        if (self.orderBook.Bids.length > 0 && now - self.preCalc > (CalcNetInterval * 1000)) {
            self.preCalc = now
            var net = _N(account.Balance + account.FrozenBalance + self.orderBook.Bids[0].Price * (account.Stocks + account.FrozenStocks))
            if (net != self.preNet) {
                self.preNet = net
                LogProfit(net)
            }
        }
        self.btc = account.Stocks
        self.cny = account.Balance
        self.p = self.btc * self.prices[self.prices.length-1] / (self.btc * self.prices[self.prices.length-1] + self.cny)
        var balanced = false
        
        if (self.p < 0.48) {
            Log("开始平衡", self.p)
            self.cny -= 300
            if (self.orderBook.Bids.length >0) {
                exchange.Buy(self.orderBook.Bids[0].Price + 0.00, 0.01)
                exchange.Buy(self.orderBook.Bids[0].Price + 0.01, 0.01)
                exchange.Buy(self.orderBook.Bids[0].Price + 0.02, 0.01)
            }
        } else if (self.p > 0.52) {
            Log("开始平衡", self.p)
            self.btc -= 0.03
            if (self.orderBook.Asks.length >0) {
                exchange.Sell(self.orderBook.Asks[0].Price - 0.00, 0.01)
                exchange.Sell(self.orderBook.Asks[0].Price - 0.01, 0.01)
                exchange.Sell(self.orderBook.Asks[0].Price - 0.02, 0.01)
            }
        }
        Sleep(BalanceTimeout)
        var orders = exchange.GetOrders()
        if (orders) {
            for (var i = 0; i < orders.length; i++) {
                if (orders[i].Id != self.tradeOrderId) {
                    exchange.CancelOrder(orders[i].Id)
                }
            }
        }
    }

    self.poll = function() {
        self.numTick++
        self.updateTrades()
        self.updateOrderBook()
        self.balanceAccount()
        
        var burstPrice = self.prices[self.prices.length-1] * BurstThresholdPct
        var bull = false
        var bear = false
        var tradeAmount = 0
        if (self.account) {
            LogStatus(self.account, 'Tick:', self.numTick, ', lastPrice:', self.prices[self.prices.length-1], ', burstPrice: ', burstPrice)
        }
        
        if (self.numTick > 2 && (
            self.prices[self.prices.length-1] - _.max(self.prices.slice(-6, -1)) > burstPrice ||
            self.prices[self.prices.length-1] - _.max(self.prices.slice(-6, -2)) > burstPrice && self.prices[self.prices.length-1] > self.prices[self.prices.length-2]
            )) {
            bull = true
            tradeAmount = self.cny / self.bidPrice * 0.99
        } else if (self.numTick > 2 && (
            self.prices[self.prices.length-1] - _.min(self.prices.slice(-6, -1)) < -burstPrice ||
            self.prices[self.prices.length-1] - _.min(self.prices.slice(-6, -2)) < -burstPrice && self.prices[self.prices.length-1] < self.prices[self.prices.length-2]
            )) {
            bear = true
            tradeAmount = self.btc
        }
        if (self.vol < BurstThresholdVol) {
            tradeAmount *= self.vol / BurstThresholdVol
        }
        
        if (self.numTick < 5) {
            tradeAmount *= 0.8
        }
        
        if (self.numTick < 10) {
            tradeAmount *= 0.8
        }
        
        if ((!bull && !bear) || tradeAmount < MinStock) {
            return
        }
        var tradePrice = bull ? self.bidPrice : self.askPrice
        while (tradeAmount >= MinStock) {
            var orderId = bull ? exchange.Buy(self.bidPrice, tradeAmount) : exchange.Sell(self.askPrice, tradeAmount)
            Sleep(200)
            if (orderId) {
                self.tradeOrderId = orderId
                var order = null
                while (true) {
                    order = exchange.GetOrder(orderId)
                    if (order) {
                        if (order.Status == ORDER_STATE_PENDING) {
                            exchange.CancelOrder(orderId)
                            Sleep(200)
                        } else {
                            break
                        }
                    }
                }
                self.tradeOrderId = 0
                tradeAmount -= order.DealAmount
                tradeAmount *= 0.9
                if (order.Status == ORDER_STATE_CANCELED) {
                    self.updateOrderBook()
                    while (bull && self.bidPrice - tradePrice > 0.1) {
                        tradeAmount *= 0.99
                        tradePrice += 0.1
                    }
                    while (bear && self.askPrice - tradePrice < -0.1) {
                        tradeAmount *= 0.99
                        tradePrice -= 0.1
                    }
                }
            }
        }
        self.numTick = 0
    }
    return self
}

function main() {
    var reaper = LeeksReaper()
    while (true) {
        reaper.poll()
        Sleep(TickInterval)
    }
}

Artikel ini membahas tentang strategi

Pada umumnya, untuk mempelajari sebuah strategi, ketika membaca, pertama-tama perhatikan struktur program secara keseluruhan. Kode strategi ini tidak banyak, hanya kurang dari 200 baris kode, dapat dikatakan sangat ramping, dan untuk versi asli, strategi rendering sangat tinggi, pada dasarnya sama.main()Fungsi dimulai untuk dijalankan, kode kebijakan berbunyi, kecualimain()Ini adalah sebuah proyek yang disebutLeeksReaper()Jadi, jika kita menghitung fungsi ini,LeeksReaper()Fungsi ini juga dapat dipahami dengan baik, yang dapat dipahami sebagai fungsi konstruksi dari modul logika strategi mesin pemetik kedelai (sebuah objek), dengan kata sederhana.LeeksReaper()Dia adalah orang yang bertanggung jawab untuk membangun logika perdagangan mesin pemetik lobak.

Kata Kunci:img img

  • StrategimainFungsi baris pertama:var reaper = LeeksReaper()Jadi, kode yang menyatakan variabel lokal.reaper, kemudian memanggil fungsi LeeksReaper (,) untuk membangun objek logika strategi yang memberikan nilai kepadareaper

  • StrategimainFungsi berikut ini:

    while (true) {
        reaper.poll()
        Sleep(TickInterval)
    }
    

    masuk kewhileSiklus Kematian, Eksekusi BerkelanjutanreaperFungsi pengolahan objekpoll()poll()Fungsi adalah logika utama dari strategi perdagangan, dan seluruh proses strategi dimulai dengan logika perdagangan yang terus-menerus dijalankan. Bagaimana denganSleep(TickInterval)Garis ini dipahami dengan baik untuk mengontrol waktu istirahat setelah setiap logika transaksi keseluruhan dijalankan, yang bertujuan untuk mengontrol frekuensi putaran logika transaksi.

MembedahLeeksReaper()Fungsi konstruksi

Lihatlah.LeeksReaper()Bagaimana fungsi membangun obyek logika strategi?

LeeksReaper()Fungsi dimulai dengan menyatakan objek kosong.var self = {}diLeeksReaper()Fungsi ini secara bertahap akan menambahkan beberapa metode, properti, dan sifat ke objek kosong ini, dan akhirnya menyelesaikan konstruksi objek ini, dan akhirnya mengembalikan objek ini.main()Dalam fungsi.var reaper = LeeksReaper()Pada langkah ini, objek yang dikembalikan diberi nilai.reaper)。

BerikanselfObyek yang ditambahkan

Berikutnya.selfDengan menambahkan banyak atribut, saya akan menjelaskan setiap atribut di bawah ini untuk memahami sifat-sifat, penggunaan, tujuan, dan strategi variabel dengan cepat, dan menghindari melihat tumpukan kode di atas awan.

    self.numTick = 0         # 用来记录poll函数调用时未触发交易的次数,当触发下单并且下单逻辑执行完时,self.numTick重置为0
    self.lastTradeId = 0     # 交易市场已经成交的订单交易记录ID,这个变量记录市场当前最新的成交记录ID
    self.vol = 0             # 通过加权平均计算之后的市场每次考察时成交量参考(每次循环获取一次市场行情数据,可以理解为考察了行情一次)
    self.askPrice = 0        # 卖单提单价格,可以理解为策略通过计算后将要挂卖单的价格
    self.bidPrice = 0        # 买单提单价格
    self.orderBook = {Asks:[], Bids:[]}    # 记录当前获取的订单薄数据,即深度数据(卖一...卖n,买一...买n)
    self.prices = []                       # 一个数组,记录订单薄中前三档加权平均计算之后的时间序列上的价格,简单说就是每次储存计算得到的订单薄前三档加权平均价格,放在一个数组中,用于后续策略交易信号参考,所以该变量名是prices,复数形式,表示一组价格
    self.tradeOrderId = 0    # 记录当前提单下单后的订单ID
    self.p = 0.5             # 仓位比重,币的价值正好占总资产价值的一半时,该值为0.5,即平衡状态
    self.account = null      # 记录账户资产数据,由GetAccount()函数返回数据
    self.preCalc = 0         # 记录最近一次计算收益时的时间戳,单位毫秒,用于控制收益计算部分代码触发执行的频率
    self.preNet = 0          # 记录当前收益数值

BerikanselfMetode penambahan objek

Setelah menambahkan sifat-sifat ini pada self, kita mulai memberikanselfObyek menambahkan metode yang memungkinkan objek untuk melakukan beberapa pekerjaan dan memiliki beberapa fungsi.

Fungsi pertama yang ditambahkan:

    self.updateTrades = function() {
        var trades = _C(exchange.GetTrades)  # 调用FMZ封装的接口GetTrades,获取当前最新的市场成交数据
        if (self.prices.length == 0) {       # 当self.prices.length == 0时,需要给self.prices数组填充数值,只有策略启动运行时才会触发
            while (trades.length == 0) {     # 如果近期市场上没有更新的成交记录,这个while循环会一直执行,直到有最新成交数据,更新trades变量
                trades = trades.concat(_C(exchange.GetTrades))   # concat 是JS数组类型的一个方法,用来拼接两个数组,这里就是把“trades”数组和“_C(exchange.GetTrades)”返回的数组数据拼接成一个数组
            }
            for (var i = 0; i < 15; i++) {   # 给self.prices填充数据,填充15个最新成交价格
                self.prices[i] = trades[trades.length - 1].Price
            }
        }
        self.vol = 0.7 * self.vol + 0.3 * _.reduce(trades, function(mem, trade) {  # _.reduce 函数迭代计算,累计最新成交记录的成交量
            // Huobi not support trade.Id
            if ((trade.Id > self.lastTradeId) || (trade.Id == 0 && trade.Time > self.lastTradeId)) {
                self.lastTradeId = Math.max(trade.Id == 0 ? trade.Time : trade.Id, self.lastTradeId)
                mem += trade.Amount
            }
            return mem
        }, 0)

    }

updateTradesFungsi ini berfungsi untuk mendapatkan data transaksi pasar terbaru, dan melakukan beberapa perhitungan dan catatan berdasarkan data tersebut, yang disediakan untuk digunakan dalam logika yang diikuti oleh strategi. Saya menulisnya langsung di dalam kode di atas. Untuk_.reduceDi sini, saya akan menjelaskan secara singkat bagaimana cara membuat program yang dapat digunakan oleh siswa yang tidak memiliki pengetahuan tentang pemrograman._.reduceYa.Underscore.jsFungsi dari perpustakaan ini, kebijakan FMZJS mendukung perpustakaan ini, sehingga mudah digunakan untuk perhitungan iterasi, dan sangat mudah digunakan untuk perhitungan iterasi.Underscore.js资料链接

Kata-kata ini memiliki arti yang sederhana, misalnya:

function main () {
   var arr = [1, 2, 3, 4]
   var sum = _.reduce(arr, function(ret, ele){
       ret += ele
       
       return ret
   }, 0)

   Log("sum:", sum)    # sum 等于 10
}

Jadi kita bisa menghitung.[1, 2, 3, 4]Jadi, jika kita menambahkan setiap angka di atasnya, maka kita akan kembali ke strategi kita, yaitu menambahkan setiap angka.tradesSetiap data catatan transaksi dalam aritmatika di mana jumlah transaksi ditambahkan. Hasilkan total volume transaksi catatan transaksi terbaru.self.vol = 0.7 * self.vol + 0.3 * _.reduce(...)Saya ingin menggunakan ini....Jadi, jika Anda ingin mengubah kode ke kode lain, Anda harus mengubahnya ke kode yang lain.self.volPerhitungan ini juga merupakan rata-rata yang ditimbang; yaitu total transaksi yang dihasilkan paling baru memiliki bobot 30%, sedangkan transaksi yang dihasilkan dari perhitungan yang ditimbang terakhir memiliki bobot 70%. Perbandingan ini ditetapkan oleh penulis strategi dan mungkin terkait dengan observasi hukum pasar. Dan jika Anda bertanya kepada saya, apa yang harus saya lakukan jika saya mendapatkan data transaksi terbaru dan antarmuka itu mengembalikan data lama yang berulang, apakah data yang saya dapatkan adalah data yang salah dan apakah ada gunanya?

if ((trade.Id > self.lastTradeId) || (trade.Id == 0 && trade.Time > self.lastTradeId)) {
    ...
}

Penghakiman ini dapat dibuat berdasarkan ID transaksi dalam catatan transaksi, yang hanya memicu akumulasi jika ID lebih besar dari ID yang tercatat sebelumnya, atau jika antarmuka pertukaran tidak memberikan ID.trade.Id == 0Dengan menggunakan timestamp dari catatan transaksi, Anda dapat menentukan saat ini.self.lastTradeIdYang disimpan adalah timestamp dari catatan transaksi, bukan ID.

Fungsi kedua yang ditambahkan:

    self.updateOrderBook = function() {
        var orderBook = _C(exchange.GetDepth)
        self.orderBook = orderBook
        if (orderBook.Bids.length < 3 || orderBook.Asks.length < 3) {
            return
        }
        self.bidPrice = orderBook.Bids[0].Price * 0.618 + orderBook.Asks[0].Price * 0.382 + 0.01
        self.askPrice = orderBook.Bids[0].Price * 0.382 + orderBook.Asks[0].Price * 0.618 - 0.01
        self.prices.shift()
        self.prices.push(_N((orderBook.Bids[0].Price + orderBook.Asks[0].Price) * 0.35 +
            (orderBook.Bids[1].Price + orderBook.Asks[1].Price) * 0.1 +
            (orderBook.Bids[2].Price + orderBook.Asks[2].Price) * 0.05))
    }

Lihatlah selanjutnyaupdateOrderBookFungsi ini, seperti yang dapat dilihat dari nama fungsi secara harfiah, fungsi ini berfungsi untuk memperbarui order thin. Namun, tidak hanya hanya memperbarui order thin. Fungsi ini mulai memanggil fungsi API FMZ.GetDepth()Dapatkan data order tipis pasar saat ini (menjual satu...menjual n, membeli satu...membeli n) dan catat data order tipis diself.orderBookKemudian, jika order data tipis, pembelian atau penjualan kurang dari 3 lembar, maka fungsi tidak valid akan dikembalikan langsung.

Setelah itu, dua data dihitung:

  • Perhitungan harga pesanan Harga invoice juga dihitung dengan menggunakan perhitungan rata-rata tertimbang, untuk perhitungan pembayaran, hak untuk membeli lebih besar yaitu 61.8% ((0.618), dan hak untuk menjual sebesar 38.2% ((0.382) Untuk menghitung harga jual beli, harga jual beli juga lebih besar. Untuk alasan mengapa 0.618, mungkin karena penulis lebih menyukai perpaduan emas. Untuk harga titik akhir ditambah dikurangi titik (<0.01) adalah untuk sedikit lebih sedikit dari pusat neraca.

  • Pembaruan urutan waktu order tipis tiga baris pertama ditambah harga rata-rata Untuk pembelian tiga kelas pertama, harga jual dilakukan perhitungan rata-rata, berat kelas pertama 0,7, berat kelas kedua 0,2, berat kelas ketiga 0,1. Beberapa teman mungkin berkata: "Oh, tidak benar, kayu dalam kode memiliki 0,7, 0,2, 0,1 ya". Kita mulai menghitungnya:

    (买一 + 卖一) * 0.35 + (买二 + 卖二) * 0.1 + (买三 + 卖三) * 0.05
    ->
    (买一 + 卖一) / 2 * 2 * 0.35 + (买二 + 卖二) / 2 * 2 * 0.1 + (买三 + 卖三) / 2 * 2 * 0.05
    ->
    (买一 + 卖一) / 2 * 0.7 + (买二 + 卖二) / 2 * 0.2 + (买三 + 卖三) / 2 * 0.1
    ->
    第一档平均的价格 * 0.7 + 第二档平均的价格 * 0.2 + 第三档平均的价格 * 0.1
    

    Dari sini kita bisa melihat bahwa harga yang dihitung akhirnya sebenarnya adalah posisi harga dari tiga kelas menengah yang diperdagangkan di pasar saat ini. Dan kemudian dengan harga yang dihitung, Anda memperbarui.self.pricesArray, keluarkan data tertua (((denganshift()Fungsi), memperbarui ke data terbaru ((denganpush()Fungsi, shift, atau push adalah metode untuk objek aritmatika bahasa JS, yang secara khusus dapat ditanyakan oleh JS.self.pricesArray adalah aliran data yang memiliki urutan waktu.

Tumis, minum air mulut, sampai di sini, sampai jumpa nanti.


Lebih banyak

Saya yang semakin kuatSaya ingin bertanya padamu.self.prices sebelum mengisi 15 harga transaksi historis, lalu mengisi tiga nilai rata-rata tertimbang di awal pesanan.

SNLPPSaya ingin memberikan pujian untuk mimpi.

m0606Sayangnya, banyak pedagang pasar telah menekan harga jual beli dengan hanya satu tik, sehingga tidak ada gunanya untuk mencoba memasukkan strategi ini ke dalam operasi jual beli.

IbuTerima kasih, saya menulis versi python yang berjalan dengan baik di Bitcoin, itu adalah mesin pemetik biaya kerja.

BtwxiaokSangat bagus, tanpa tafsiran mimpi, saya benar-benar tidak bisa memahami sepenuhnya, terima kasih atas kesabaran Anda!

Eddie.Pembagian emas 0.618 0.382 adalah Fibro yang digunakan Rumput Rumput

Aku tidak tahu.Ini benar-benar banyak sapi, sangat rinci.

Evan1987Terima kasih atas jawabannya yang sangat rinci.

membuatmimpi total sapi p

Syi'im"Mengharukan" adalah kata yang sering diucapkan oleh para pengunjuk rasa. Meskipun ada komentarnya, namun tampaknya sangat rumit...

Sembilan Matahari"Mengharukan, banyak sapi!"

Mimpi kecilSaya tidak tahu.

Mimpi kecilDi sini, Anda dapat menemukan beberapa cara untuk mendapatkan keuntungan dari trading Forex.

Mimpi kecilJika Anda tidak mau, Anda dapat membaca artikel yang ditulis oleh Grasshopper yang menganalisis prinsip-prinsip strategi, strategi frekuensi tinggi membutuhkan dukungan.

Mimpi kecilTerima kasih atas dukungannya ~ Jika Anda suka, bantu saya berbagi, ya ~

Mimpi kecilTerima kasih atas dukungannya!

Mimpi kecilTerima kasih atas dukungannya!

Mimpi kecilTerima kasih atas dukungannya!

Mimpi kecilSaat masuk sekolah, saya sangat ingat rasio perpisah emas ini dan mengatakan bahwa rasio panjang lebar ini adalah persegi panjang yang paling indah~~ tetapi tidak tahu mengapa.

Mimpi kecilTerima kasih atas dukungannya.

Mimpi kecilPada kenyataannya tidak rumit, perbandingan ini sangat rumit, baris demi baris dijelaskan dengan cara yang paling mudah dimengerti.