Type/to search
8
Follow
1361
Followers
ネギ収穫機戦略の分析(2)
HFT
Created 2020-11-16 10:03:52  Updated 2024-12-05 22:03:01
 23
 8482

img

ネギ収穫機戦略の分析(2)

それから以前のコンテンツ説明する。

3番目に追加された機能:

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

コンストラクタLeeksReaper()オブジェクトを構築するときは、balanceAccount()この機能は、アカウント資産情報を更新するもので、self.accountつまり、構築されたオブジェクトaccount財産。利益値を定期的に計算して印刷します。そして、最新の口座資産情報をもとに、スポット通貨残高比率(スポットポジション残高)を算出し、乖離閾値に達した時点で小口注文を決済し、通貨(ポジション)を均衡状態に戻します。取引が完了するまで一定時間待機し、保留中の注文をすべてキャンセルします。この関数の次回の実行では、残高が再度確認され、対応する処理が行われます。

この関数のコードを行ごとに見てみましょう。
最初の文var account = exchange.GetAccount()ローカル変数を宣言するaccount、Inventor APIインターフェースを呼び出すexchange.GetAccount()関数は、現在のアカウントの最新データを取得し、それをaccount変数。それで判断するaccountこの変数は、変数がnull値(タイムアウト、ネットワーク、交換インターフェース例外など)の取得に失敗した場合は、直接返されます(if (!account){...}ここ)。

self.account = accountこの文はローカル変数に関するものですaccount構築されたオブジェクトに割り当てられるaccount属性は、構築されたオブジェクトに最新のアカウント情報を記録するために使用されます。

var now = new Date().getTime()この文はローカル変数を宣言するnow、JavaScript言語の時間と日付のオブジェクトを呼び出すgetTime()この関数は現在のタイムスタンプを返します。割り当て先now変数。

if (self.orderBook.Bids.length > 0 && now - self.preCalc > (CalcNetInterval * 1000)) {...}このコードは、現在のタイムスタンプと最後に記録されたタイムスタンプの差がパラメータを超えているかどうかを判定します。CalcNetInterval * 1000これは、前回の更新から現在までに、CalcNetInterval * 1000ミリ秒(CalcNetInterval収入のタイミング印刷機能を実現するために、1秒単位で設定されています。収入の計算には最初の入札価格が使用されるため、条件も制限されています。self.orderBook.Bids.length > 0この条件 (深度データ、購入注文リストに有効なギア情報が含まれている必要があります)。このif文の条件が成立すると、実行self.preCalc = now最新の印刷収益のタイムスタンプ変数を更新するself.preCalc現在のタイムスタンプnow。ここでの所得統計は純額計算法を使用しており、コードはvar net = _N(account.Balance + account.FrozenBalance + self.orderBook.Bids[0].Price * (account.Stocks + account.FrozenStocks))つまり、現在の購入価格に応じてコインをお金(分母)に変換し、それをアカウントの金額に追加して、宣言されたローカル変数に割り当てます。net。現在の純額合計が前回記録された純額合計と一致しているかどうかを判断します。

python
if (net != self.preNet) { self.preNet = net LogProfit(net) }

矛盾がある場合は、net != self.preNet真の場合、net変数は純額を記録するために使用されるプロパティを更新しますself.preNet。これを印刷しますnet発明者の定量取引プラットフォームロボットの利益曲線チャートへの総純資産データ(FMZ APIドキュメントで照会可能)LogProfitこの機能)。

スケジュールされた印刷収益がトリガーされない場合は、次のプロセスを続行します。account.Stocks(現在の口座で利用可能なコインの数)、account.Balance(口座に現在残っている金額)は、self.btcself.cny。オフセット比率を計算し、その値をレコードに割り当てるself.p

python
self.p = self.btc * self.prices[self.prices.length-1] / (self.btc * self.prices[self.prices.length-1] + self.cny)

アルゴリズムも非常にシンプルで、コインの現在の価値をアカウントの合計純価値のパーセンテージとして計算します。

では、お金の残高(ポジション)がいつトリガーされるかをどのように判断するのでしょうか?
著者は50%の上下2パーセントをバッファーとして使い、バッファーを超えたバランス、つまりself.p < 0.48コインバランス偏差が発動し、コインが少なくなったと考えられるので、相場のポジションで買いを開始し、その都度0.01ずつ価格を上げ、小口注文を3つ出します。同様に通貨バランスself.p > 0.52コインが多すぎると思われる場合は、始値で売ることで少量注文を出すことができます。最後に、パラメータ設定に従って一定時間待ちますSleep(BalanceTimeout)それ以降のご注文はすべてキャンセルとなります。

python
var orders = exchange.GetOrders() # 获取当前所有挂单,存在orders变量 if (orders) { # 如果获取当前挂单数据的变量orders不为null for (var i = 0; i < orders.length; i++) { # 循环遍历orders,逐个取消订单 if (orders[i].Id != self.tradeOrderId) { exchange.CancelOrder(orders[i].Id) # 调用exchange.CancelOrder,根据orders[i].Id取消订单 } } }

4番目に追加された機能:

戦略の核心部分、ハイライトはここにあります。self.poll = function() {...}関数は戦略全体の主なロジックです。前回の記事でもこれについて説明しました。main()関数の実行が開始され、while無限ループの前に、var reaper = LeeksReaper()ネギ収穫機のオブジェクトを構築し、main()関数内のループ呼び出しreaper.poll()これが呼び出される関数です。

self.poll関数は実行を開始し、各ループの前にいくつかの準備作業を行います。self.numTick++カウントを増やして、self.updateTrades()最新の市場取引記録を更新し、関連データを計算します。self.updateOrderBook()注文簿データを更新し、関連データを計算します。self.balanceAccount()資金(ポジション)残高を確認します。

python
var burstPrice = self.prices[self.prices.length-1] * BurstThresholdPct # 计算爆发价格 var bull = false # 声明牛市标记的变量,初始为假 var bear = false # 声明熊市标记的变量,初始为假 var tradeAmount = 0 # 声明交易数量变量,初始为0

次のステップは、現在の短期市場が強気か弱気かを判断することです。

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

前回の記事を思い出してくださいself.updateOrderBook()関数では、加重平均アルゴリズムを使用して、順序付きの時系列を構築します。prices配列。このコードでは3つの新しい関数が使用されています_.min_.maxsliceこれら3つの機能も非常にわかりやすいです。

  • _.min: その機能は、パラメータ配列内の最小値を見つけることです。

  • _.max: その機能は、パラメータ配列内の最大値を見つけることです。

  • slice: この関数は、JavaScript 配列オブジェクトのメンバー関数です。その機能は、インデックスに従って配列の一部をインターセプトして返すことです。例:

    javascript
    function main() { // index .. -8 -7 -6 -5 -4 -3 -2 -1 var arr = [9, 8, 7, 6, 5, 4, 3, 2, 1, 0] Log(arr.slice(-5, -1)) // 会截取 4 ~ 1 这几个元素,返回一个新数组:[4,3,2,1] }

    img

ここで弱気と強気を判断する条件は次のとおりです。

  • self.numTick > 2これが確立されるには、新しい検出価格がブレイクアウトしたときに、最初にトリガーされるのを避けるために、少なくとも 3 回の検出ラウンドの後にトリガーされる必要があることを意味します。
  • 価格シリーズself.prices最後のデータはself.prices配列の前の範囲の最高価格と最低価格の差は、burstPriceこれが爆安価格です。

すべての条件が満たされている場合は、マークを付けますbullまたはbear、のためにtrue、そして与えるtradeAmount変数を割り当ててスタッド取引を計画します。

前回のself.updateTrades()関数内で更新および計算self.vol、パラメータBurstThresholdVol取引の強度を下げる(計画されている取引の規模を縮小する)かどうかを決定します。

python
if (self.vol < BurstThresholdVol) { tradeAmount *= self.vol / BurstThresholdVol // 缩减计划交易量,缩减为之前量的self.vol / BurstThresholdVol 倍 } if (self.numTick < 5) { tradeAmount *= 0.8 // 缩减为计划的80% } if (self.numTick < 10) { // 缩减为计划的80% tradeAmount *= 0.8 }

次に、取引シグナルと取引量が要件を満たしているかどうかを判断します。

python
if ((!bull && !bear) || tradeAmount < MinStock) { # 如果非牛市并且也非熊市,或者计划交易的量tradeAmount小于参数设置的最小交易量MinStock,poll函数直接返回,不做交易操作 return }

上記の判断の後、var tradePrice = bull ? self.bidPrice : self.askPrice弱気相場か強気相場かに応じて取引価格を設定し、対応する船荷証券価格に値を割り当てます。

最後に入力してくださいwhileループを止める唯一の条件はtradeAmount >= MinStock予定取引量が最小取引量を下回っています。
ループでは、現在の市場が強気か弱気かに基づいて注文が行われます。注文IDを変数に記録しますorderId。注文のたびにSleep(200)200 ミリ秒待機します。そして、ループ内で判断するorderId条件が true の場合、それは true です (注文が失敗した場合、注文 ID は返されず、if 条件はトリガーされません)。注文IDを取得して割り当てるself.tradeOrderId

注文データを格納する変数を宣言するorder初期値はnull。次に、このIDの注文データを取得するためにループし、注文が保留中の注文状態にあるかどうかを判断します。保留中の注文状態にある場合は、このIDの注文をキャンセルします。保留中の注文状態でない場合は、このループから抜け出します。検出ループ。

pine
var order = null // 声明一个变量用于保存订单数据 while (true) { // 一个while循环 order = exchange.GetOrder(orderId) // 调用GetOrder查询订单ID为 orderId的订单数据 if (order) { // 如果查询到订单数据,查询失败order为null,不会触发当前if条件 if (order.Status == ORDER_STATE_PENDING) { // 判断订单状态是不是正在挂单中 exchange.CancelOrder(orderId) // 如果当前正在挂单,取消该订单 Sleep(200) } else { // 否则执行break跳出当前while循环 break } } }

次に、以下のプロセスに従います。

pine
self.tradeOrderId = 0 // 重置self.tradeOrderId tradeAmount -= order.DealAmount // 更新tradeAmount,减去提单的订单已经成交的数量 tradeAmount *= 0.9 // 减小下单力度 if (order.Status == ORDER_STATE_CANCELED) { // 如果订单已经是取消了 self.updateOrderBook() // 更新订单薄等数据 while (bull && self.bidPrice - tradePrice > 0.1) { // 牛市时,更新后的提单价格超过当前交易价格0.1就减小交易力度,略微调整交易价格 tradeAmount *= 0.99 tradePrice += 0.1 } while (bear && self.askPrice - tradePrice < -0.1) { // 熊市时,更新后的提单价格超过当前交易价格0.1就减小交易力度,略微调整交易价格 tradeAmount *= 0.99 tradePrice -= 0.1 } }

プログラムの流れが飛び出すとwhile (tradeAmount >= MinStock) {...}このサイクルは、価格爆発取引プロセスが完了したことを示します。
埋め込むself.numTick = 0つまりリセットself.numTick0です。

LeeksReaper()コンストラクタは最終的に実行されるself返されるオブジェクトはvar reaper = LeeksReaper()返却されたときreaper

これまでのところLeeksReaper()コンストラクタがネギ収穫機オブジェクトを構築する方法、ネギ収穫機オブジェクトのさまざまなメソッド、および主要な論理関数の実行プロセスを分析しました。この記事を読んだ後、高頻度の理解がより明確になったと思います。戦略アルゴリズムのプロセス。理解します。

Related Recommendations
Comment
All comments (19)

    感谢梦总。梦总,请问韭菜收割机跟草神的高频机器人两者结合的思路有没有搞头啊?

    4 years ago

    草神有篇文章讲过,高频需要有市场环境。策略而言韭菜收割机跟草神的高频机器人有思路上的共同点。

    4 years ago

    说了一堆废话。核心的一句都没讲。

    4 years ago

    实在抱歉,这个文章主要是给入门初学者讲执行流程的,讲了一堆废话确实扎眼了,您忽略就行了。

    4 years ago

    有一点不明白,为什么一定要保持币和钱的平衡,如果没有达到平衡,就得操作买和卖。之后过BalanceTimeout又取消订单,不再平衡,而是进入下一个爆发环节。

    5 years ago

    下单命令在哪里。。。

    5 years ago

    之前看的云里雾里,用了一阵FMZ,重新看了一遍。总结思路来说。这个策略的思路是:
    监控盘口价格异动,发现价格爆发,顺着趋势的方向,以交易量大小作为参照计算出梭哈百分比,进行梭哈交易。梭哈交易完以后不持仓,长期保持一个币钱平衡的状态。
    我说的对吗,梦总?嘿嘿。

    5 years ago

    great !~

    5 years ago

    请教梦总,程序不停的在平衡币和钱,这个功能出于什么考虑?去掉balanceAccount()程序会怎样发展?

    5 years ago

    原版韭菜收割机是有一个平衡模块,可以考虑去掉。具体影响不太清楚了。

    5 years ago

    感谢梦总,fmz真的是大宝库

    5 years ago

    不客气 ~

    5 years ago

    还是看不明白

    5 years ago

    ~囧~

    5 years ago

    BurstThresholdVol 这个参数是干嘛的?该怎么设置啊

    6 years ago

    爆发量,这个是策略参数,人为设置的,详细看下策略、文章,就知道这个变量控制什么了。

    6 years ago

    细节满满,看了1小时才勉强理解细节,赞

    6 years ago

    梦总666,研究明白后我能写出跟print money 一样的韭菜收割机么

    6 years ago

    原理应该是差不多吧

    6 years ago
  • 1
iPhone Download
Forums
PINE Language
© 2015 - ∞ INVENTOR PTE LTD (SG)