Sumber dimuat naik... memuat...

Penggambaran teknik mesin pemetik lobak (1)

Penulis:Pencipta Kuantiti - Impian Kecil, Dicipta: 2020-11-12 22:11:32, Dikemas kini: 2024-12-06 22:20:54

img

Kaedah pemangkasan mesin pemetik lobak

Pencipta baru-baru ini membincangkan kuantiti dalam kumpulan WeChatprint moneyPada bulan Julai lalu, seorang pekerja robot yang dikenali dengan nama Robots of the Future (Robot of the Future), yang dibincangkan dengan sangat panas, membuat satu strategi yang sangat lama kembali ke dalam pandangan orang ramai:Mesin pemetik lobakprint moneyPrinsip perdagangan robot yang diambil dari strategi pemetik lobak, menyalahkan dirinya ketika itu untuk strategi pemetik lobak tidak terlalu jelas dan tidak difahami. Oleh itu, melihat semula strategi asal dan melihat semula versi pemindahan yang diukur oleh pencipta.Pemangsa lobak OKCoin dipindahkanSaya tidak tahu. Ia melibatkan pencipta untuk mengukur strategi mesin pemetik lobak versi platform, menguraikan strategi itu, dan menggali idea strategi itu; supaya pengguna platform dapat mempelajari idea strategi ini. Dalam artikel ini, kita lebih banyak menganalisis dari segi strategi, niat, dan lain-lain, untuk mengurangkan kandungan yang membosankan yang berkaitan dengan pengaturcaraan.

[Transport OKCoin to Cabbage Harvester] Sumber strategi:

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)
    }
}

Rujukan Strategi

Secara umum, untuk mempelajari dan membaca satu strategi, pertama-tama lihat struktur keseluruhan program. Kod strategi ini tidak banyak, hanya kurang daripada 200 baris kod, sangat ringkas, dan untuk versi asal, kod strategi yang sangat tinggi, pada dasarnya sama.main()Fungsi mula dijalankan, menyambung kod dasar, kecualimain()Ia adalah satu jenama.LeeksReaper()Dan jika kita mempunyai fungsi yang sama,LeeksReaper()Fungsi juga dapat difahami dengan baik, yang boleh difahami sebagai fungsi pembinaan untuk modul logik strategi pemetik lobak (sebuah objek), secara ringkas.LeeksReaper()Ia bertanggungjawab untuk membina logik perdagangan mesin pemetik lobak.

Kata Kunci:img img

  • StrategimainBarisan pertama fungsi:var reaper = LeeksReaper()Kod ini mengisytiharkan satu pembolehubah tempatan.reaper, kemudian memanggil fungsi LeeksReaper (), yang membina objek logik strategi yang memberi nilai kepadareaper

  • StrategimainFungsi seterusnya:

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

    masuk ke dalamwhileSiklus Kematian, Pelaksanaan BerterusanreaperFungsi pemprosesan objekpoll()poll()Fungsi adalah logik utama strategi dagangan, dan keseluruhan prosedur strategi bermula dengan logik pelaksanaan dagangan yang berterusan. MengenaiSleep(TickInterval)Barisan ini difahami dengan baik untuk mengawal masa hentian selepas setiap pelaksanaan logik dagangan secara keseluruhan, yang bertujuan untuk mengawal frekuensi putaran logik dagangan.

PenggambaranLeeksReaper()Fungsi pembinaan

Lihatlah.LeeksReaper()Bagaimana fungsi membina objek logik strategi?

LeeksReaper()Fungsi bermula dengan mengisytiharkan objek kosong.var self = {}DalamLeeksReaper()Dalam proses pelaksanaan, fungsi akan secara beransur-ansur menambah beberapa kaedah, sifat kepada objek kosong ini, akhirnya menyelesaikan pembinaan objek ini, dan akhirnya mengembalikan objek ini (iaitumain()Dalam fungsi.var reaper = LeeksReaper()Pada tahap ini, objek yang dikembalikan diberi nilai.reaper)。

BerikanselfObjek menambah sifat

Berikan kepadaselfBanyak sifat telah ditambah, dan di bawah ini saya menerangkan setiap sifat untuk memahami sifat-sifat, kegunaan, niat, dan strategi yang mudah untuk memahami, dan mengelakkan melihat set kod ini, yang dikelilingi oleh 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          # 记录当前收益数值

BerikanselfKaedah penambahan objek

Selepas anda menambah sifat-sifat ini kepada self, anda akan mula memberikanselfObjek menambah kaedah untuk membolehkan objek ini melakukan beberapa tugas dan mempunyai beberapa fungsi.

Fungsi pertama yang ditambahkan ialah:

    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 adalah untuk mendapatkan data transaksi pasaran yang terkini, dan membuat beberapa pengiraan dan rekod berdasarkan data, yang disediakan untuk digunakan dalam logik susulan strategi. Saya menulisnya secara langsung dalam kod di atas. Untuk_.reduceDi sini, saya akan menjelaskan secara ringkas, bagaimana anda boleh membuat program yang anda sukai dan bagaimana anda boleh menggunakannya._.reduceYa.Underscore.jsFungsi dalam perpustakaan ini, yang disokong oleh dasar FMZJS, jadi mudah digunakan untuk pengiraan berulang.Underscore.js资料链接

Maksudnya juga mudah, contohnya:

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 boleh mengumpul[1, 2, 3, 4]Setiap nombor di dalamnya dijumlahkan.tradesSetiap data rekod transaksi dalam aritmatik di mana jumlah transaksi ditambahkan. Hasilkan jumlah transaksi rekod transaksi terkini.self.vol = 0.7 * self.vol + 0.3 * _.reduce(...)Boleh saya gunakan?...Di sini anda boleh lihat bagaimana ia berfungsi untuk menghapuskan semua kod.self.volPerkiraan ini juga merupakan purata berat; iaitu, jumlah dagangan yang dihasilkan terbaru adalah 30% daripada jumlah dagangan yang dihasilkan pada kali terakhir; perbandingan ini ditetapkan oleh penulis strategi dan mungkin berkaitan dengan pemantauan undang-undang pasaran. Jika anda bertanya kepada saya, apa yang akan saya lakukan jika antara muka yang mengambil data transaksi baru-baru ini mengembalikan data lama yang berulang, dan data yang saya dapat adalah salah, dan ada gunanya?

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

Penghakiman ini boleh dibuat berdasarkan penghakiman ID urus niaga dalam rekod urus niaga, hanya apabila ID lebih besar daripada ID yang direkodkan sebelum ini yang mencetuskan akumulasi, atau jika ID tidak diberikan oleh antara muka bursa, iaitu:trade.Id == 0Dalam kes ini, anda boleh menggunakan tanda masa dalam rekod urus niaga untuk membuat keputusan.self.lastTradeIdYang disimpan ialah timestamp rekod transaksi, bukan ID.

Fungsi kedua yang ditambahkan ialah:

    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))
    }

Cuba lihat.updateOrderBookFungsi ini, seperti yang dapat dilihat dari nama fungsi secara harfiah, fungsi ini berfungsi untuk mengemas kini order thin.GetDepth()Dapatkan data order tipis pasaran semasa (jual satu... jual n, beli satu... beli n) dan mencatat data order tipis diself.orderBookDalam kes ini, jika pesanan data tipis, pembelian atau penjualan kurang daripada 3 baris, fungsi tidak sah akan dikembalikan secara langsung.

Selepas itu, dua data dikira:

  • Mengira harga tempahan Harga bil yang dikira juga digunakan untuk mengira purata berat, untuk mengira bayaran, hak beli adalah 61.8% ((0.618), dan hak jual adalah 38.2% ((0.382) Apabila mengira harga jual beli pesanan, ia adalah sama, memberi dan menjual hak satu harga adalah lebih besar. Mengenai mengapa 0.618, mungkin pengarang lebih suka peratusan pembahagian emas. Mengenai harga titik terakhir yang ditambah dan dikurangkan ((0.01) adalah untuk sedikit lagi menyimpang sedikit dari pusat yang tepat.

  • Pembaharuan dalam urutan masa pesanan rendah tiga barisan pertama ditambah harga purata Untuk pembelian tiga baris pertama, harga pesanan dijual dengan perbandingan berat, berat baris pertama 0.7, berat baris kedua 0.2, berat baris ketiga 0.1. Mungkin ada rakan sekelas yang berkata: Oh, tidak benar, kayu dalam kod mempunyai 0.7, 0.2, 0.1 ya. Di sini, kita akan melihat bagaimana ia berfungsi.

    (买一 + 卖一) * 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, anda dapat melihat bahawa harga yang dihitung akhirnya sebenarnya adalah kedudukan harga untuk tiga kelas pertengahan yang berdagang di pasaran semasa. Kemudian, dengan harga yang dikira, anda boleh mengemas kini.self.pricesArray, keluarkan data tertua ((() melaluishift()Fungsi), mengemas kini ke dalam data terkini ((denganpush()Fungsi, shift, atau push adalah kaedah untuk objek aritmatika bahasa JS, yang secara khusus boleh ditanyakan oleh sumber JS).self.pricesArray adalah aliran data dengan urutan urutan masa.

Tikus batuk, minum air mulut, lihat di sini, sampai jumpa lagi.


Lebih lanjut

Saya yang semakin kuatSaya ingin bertanya kepada anda;self.prices sebelum mengisi 15 harga transaksi sejarah, dan kemudian mengisi tiga harga purata bertimbang berat sebelum pesanan.

SNLPPSaya ingin memberi pujian kepada impian.

m0606Malangnya, ramai peniaga telah menekan harga untuk membeli dan menjual hanya dengan satu tanda, sehingga tidak ada gunanya untuk memasukkan strategi ini ke dalam operasi membeli dan menjual di tengah.

ibuTerima kasih, saya telah menulis versi python untuk berjalan di dalam Bitcoin, ia adalah pemetik bayaran kerja.

bwxiaokSaya sangat teruja kerana tidak ada tafsiran untuk mimpi saya, saya tidak dapat memahami sepenuhnya, terima kasih atas kesabaran anda!

Eddie.Pembagian emas 0.618 0.382 digunakan dalam Fibonacci Kumpulan lembu

Tunggu.Memang banyak lembu, sangat terperinci.

Evan1987Terima kasih kerana berkongsi.

buatlahRumput p

SyahidMimpi besar, banyak lembu! Walaupun ada keterangan, tetapi ia kelihatan sangat rumit...

Sembilan MatahariMimpi besar, banyak lembu!

Pencipta Kuantiti - Impian KecilYa, saya faham.

Pencipta Kuantiti - Impian KecilIni adalah untuk belajar idea dan melihat peluang perdagangan yang boleh menjadi kerap.

Pencipta Kuantiti - Impian KecilTidak sopan, anda boleh membaca artikel analisis prinsip strategi yang ditulis oleh Grasshopper, strategi frekuensi tinggi memerlukan beberapa sokongan.

Pencipta Kuantiti - Impian KecilTerima kasih atas sokongan anda ~ jika anda suka, tolong kongsikan, ya ~

Pencipta Kuantiti - Impian KecilTerima kasih atas sokongan anda!

Pencipta Kuantiti - Impian KecilTerima kasih atas sokongan anda!

Pencipta Kuantiti - Impian KecilTerima kasih atas sokongan anda!

Pencipta Kuantiti - Impian KecilPada masa sekolah, saya teringat dengan jelas perbandingan pembahagian emas ini, mengatakan bahawa segi empat segi panjang lebar ini adalah yang paling indah~~ tetapi tidak tahu mengapa.

Pencipta Kuantiti - Impian KecilTerima kasih atas sokongan anda.

Pencipta Kuantiti - Impian KecilPada hakikatnya tidak rumit, perbandingan ini agak rumit, setiap baris diceritakan dengan cara yang paling mudah difahami.