
それから以前のコンテンツ説明する。
3番目に追加された機能:
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。現在の純額合計が前回記録された純額合計と一致しているかどうかを判断します。
if (net != self.preNet) {
self.preNet = net
LogProfit(net)
}
矛盾がある場合は、net != self.preNet真の場合、net変数は純額を記録するために使用されるプロパティを更新しますself.preNet。これを印刷しますnet発明者の定量取引プラットフォームロボットの利益曲線チャートへの総純資産データ(FMZ APIドキュメントで照会可能)LogProfitこの機能)。
スケジュールされた印刷収益がトリガーされない場合は、次のプロセスを続行します。account.Stocks(現在の口座で利用可能なコインの数)、account.Balance(口座に現在残っている金額)は、self.btc,self.cny。オフセット比率を計算し、その値をレコードに割り当てるself.p。
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)それ以降のご注文はすべてキャンセルとなります。
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()資金(ポジション)残高を確認します。
var burstPrice = self.prices[self.prices.length-1] * BurstThresholdPct # 计算爆发价格
var bull = false # 声明牛市标记的变量,初始为假
var bear = false # 声明熊市标记的变量,初始为假
var tradeAmount = 0 # 声明交易数量变量,初始为0
次のステップは、現在の短期市場が強気か弱気かを判断することです。
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,_.max,sliceこれら3つの機能も非常にわかりやすいです。
_.min: その機能は、パラメータ配列内の最小値を見つけることです。
_.max: その機能は、パラメータ配列内の最大値を見つけることです。
slice: この関数は、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]
}

ここで弱気と強気を判断する条件は次のとおりです。
self.numTick > 2これが確立されるには、新しい検出価格がブレイクアウトしたときに、最初にトリガーされるのを避けるために、少なくとも 3 回の検出ラウンドの後にトリガーされる必要があることを意味します。self.prices最後のデータはself.prices配列の前の範囲の最高価格と最低価格の差は、burstPriceこれが爆安価格です。すべての条件が満たされている場合は、マークを付けますbullまたはbear、のためにtrue、そして与えるtradeAmount変数を割り当ててスタッド取引を計画します。
前回のself.updateTrades()関数内で更新および計算self.vol、パラメータBurstThresholdVol取引の強度を下げる(計画されている取引の規模を縮小する)かどうかを決定します。
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
}
次に、取引シグナルと取引量が要件を満たしているかどうかを判断します。
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の注文をキャンセルします。保留中の注文状態でない場合は、このループから抜け出します。検出ループ。
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
}
}
}
次に、以下のプロセスに従います。
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()コンストラクタがネギ収穫機オブジェクトを構築する方法、ネギ収穫機オブジェクトのさまざまなメソッド、および主要な論理関数の実行プロセスを分析しました。この記事を読んだ後、高頻度の理解がより明確になったと思います。戦略アルゴリズムのプロセス。理解します。