
затемПредыдущее содержаниеобъяснять.
Третья добавленная функция:
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и вызовите интерфейс API Inventorexchange.GetAccount()Функция, получить последние данные текущего счета и назначить егоaccountпеременная. Тогда судитеaccountЭта переменная, если переменнаяnullЕсли значение (такое как тайм-аут, сеть, исключение интерфейса обмена и т. д.) не может быть получено, оно будет возвращено напрямую (соответствующееif (!account){...}здесь).
self.account = accountЭто предложение заключается в том, чтобы поместить локальную переменнуюaccountПрисвоено построенному объектуaccountАтрибуты используются для записи последней информации об учетной записи в созданный объект.
var now = new Date().getTime()Этот оператор объявляет локальную переменнуюnowи вызовите объект времени и даты языка JavaScriptgetTime()Функция возвращает текущую временную метку. Назначитьnowпеременная.
if (self.orderBook.Bids.length > 0 && now - self.preCalc > (CalcNetInterval * 1000)) {...}Этот код определяет, превышает ли разница между текущей временной меткой и последней записанной временной меткой параметрCalcNetInterval * 1000Это означает, что с момента последнего обновления по настоящее время болееCalcNetInterval * 1000миллисекунда(CalcNetIntervalсекунд), чтобы достичь функции синхронизации печати дохода. Поскольку цена первой ставки используется при расчете дохода, условия также ограничивают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)
Алгоритм также очень прост: он заключается в расчете текущей стоимости монеты в процентах от общей чистой стоимости счета.
Так как же определить, когда срабатывает баланс денег (позиция)?
Автор использует 2 процентных пункта выше и ниже 50% в качестве буфера и выполняет балансировку за пределами буфера, то естьself.p < 0.48Срабатывает отклонение баланса монет, и считается, что монет стало меньше, поэтому начните покупать по позиции на рынке и увеличивайте цену на 0,01 каждый раз, и разместите три небольших ордера. Аналогично, валютный баланс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取消订单
}
}
}
Четвертая добавленная функция:
Основная часть стратегии, ее суть здесь,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Множество. В этом коде используются три новые функции_.min,_.max,sliceЭти три функции также очень просты для понимания.
_.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Чтобы быть установленным, это означает, что когда начинается новый раунд цен обнаружения, он должен быть запущен как минимум после трех раундов обнаружения, чтобы избежать запуска в самом начале.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Планируемый объем транзакции меньше минимального объема транзакции.
В этом цикле ордера размещаются в зависимости от того, является ли текущий рынок бычьим или медвежьим. И запишите идентификатор заказа в переменнуюorderId. После каждого раунда заказаSleep(200)Подождите 200 миллисекунд. Тогда судите в курсеorderIdЯвляется ли это истинным (если заказ не будет выполнен, идентификатор заказа не будет возвращен и условие if не будет выполнено), если условие истинно. Получите идентификатор заказа и присвойте егоself.tradeOrderId。
Объявите переменную для хранения данных заказаorderНачальное значение равноnull. Затем выполните цикл, чтобы получить данные заказа этого идентификатора, и определите, находится ли заказ в статусе отложенного заказа. Если он находится в статусе отложенного заказа, отмените заказ этого идентификатора. Если он не находится в статусе отложенного заказа, выйдите из этого контур обнаружения.
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.numTickравно 0.
LeeksReaper()Конструктор наконец выполняетсяselfВозвращенный объект —var reaper = LeeksReaper()Когда его вернулиreaper。
До сих порLeeksReaper()Мы проанализировали, как конструктор создает объект leek harvester, различные методы объекта leek harvester и процесс выполнения основных логических функций. Я считаю, что после прочтения этой статьи у вас должно быть более четкое представление о высокочастотном алгоритм стратегии процесса. понять.