В процессе загрузки ресурсов... загрузка...

Диагностика стратегии капустного комбайна (1)

Автор:Изобретатели количественного измерения - мечты, Создано: 2020-11-12 22:11:32, Обновлено: 2024-12-06 22:20:54

img

Диагностика стратегии салатных комбайнов

Недавняя дискуссия в группе WeChat о количественных изобретателяхprint moneyПоскольку ученые не знают, что роботы могут быть полезными для людей, то они не могут быть полезными для других людей, потому что они не могут быть полезными для них.Сосновый комбайнprint moneyРобот-торговый принцип, опирающийся на стратегию капустного комбайна, обвиняет себя в том, что тогда он не был достаточно ясным и не понимал стратегии капустного комбайна. Поэтому, снова серьезно взглянуть на оригинальную стратегию и снова взглянуть на переносную версию, количественно измеренную изобретателем.Трансплантация OKCoin для капустного комбайнаЯ не знаю. В частности, разработчики планируют количественно определить стратегию переносной версии планшета, проанализировать ее и извлечь идеи из нее, чтобы пользователи платформы могли их изучить. В этой статье мы больше анализируем стратегические идеи, намерения и т.д., стараясь уменьшить количество скучных материалов, связанных с программированием.

[Портировать OKCoin в капусту-резервную машину]

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

Обзор стратегии

Обычно при изучении стратегии, при чтении, сначала просматривается общая структура программы. Эта стратегия не имеет большого количества кода, всего менее 200 строк кода, является очень утонченной и имеет высокую редуктивность к оригинальной версии стратегии, которая в основном остается такой же.main()Функция начинает выполняться, прочитайте политический код, за исключениемmain()Именно так.LeeksReaper()И мы должны сделать это.LeeksReaper()Функция также хорошо понятна, которая может быть понята как конструкторная функция логического модуля стратегии кабачного комбайна (объект), просто говоря.LeeksReaper()Он отвечает за разработку логики торговли салатными комбайнами.

Ключевые слова:img img

  • СтратегияmainПервая строка функции:var reaper = LeeksReaper()Код объявляет локальную переменную.reaper, а затем вызвать функцию LeeksReaper (), чтобы построить логический объект стратегии, который присваивает значениеreaper

  • СтратегияmainФункция следующая:

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

    Войти вwhileСмертный цикл, непрекращающиеся действияreaperФункции обработки объектовpoll()poll()Функция является основной логикой стратегии торговли, и вся стратегическая процедура начинается с непрерывного выполнения логики торговли. Что касаетсяSleep(TickInterval)Эта строка хорошо понятна, чтобы контролировать время приостановки после выполнения каждой логики сделки, чтобы контролировать частоту вращения логики сделки.

АнатомияLeeksReaper()Функции построения

Посмотрите.LeeksReaper()Как функция конструирует стратегический логический объект?

LeeksReaper()Функция начинается, объявляет пустой объект.var self = {},LeeksReaper()В процессе выполнения функция постепенно добавляет несколько методов, свойств к этому пустому объекту, в конечном итоге завершает построение этого объекта, и в конечном итоге возвращает этот объект ((, т.е.main()Внутри функции.var reaper = LeeksReaper()На этом этапе, возвращаемый объект присваиваетсяreaper)。

Дайте.selfОбъект добавляет свойства

ДалееselfДобавлено множество свойств, которые я описал ниже, чтобы быстро понять эти свойства, использование, намерения и удобство понимания стратегии, чтобы избежать того, чтобы видеть этот набор кода в тумане.

    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          # 记录当前收益数值

Дайте.selfСпособы добавления объектов

После того, как мы добавили эти свойства к самому себе, мы начинаем даватьselfОбъект добавляет методы, позволяющие этому объекту выполнять определенные задачи и обладать определенными функциями.

Первая добавленная функция:

    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)

    }

updateTradesФункция получает данные о сделках на рынке, на основе которых выполняются вычисления и записываются для использования в логике последующей стратегии. Я написал комментарии по строкам прямо в код, указанный выше. Для_.reduceЕсли вы не знаете, что такое программирование, вы можете задаться вопросом: "Что такое программирование?"_.reduceДа, это так.Underscore.jsФункции в этой библиотеке, поддерживаемые FMZJS-политикой, так что их легко использовать для ипотечных вычислений.Underscore.js资料链接

Это означает, что вы должны быть готовы к тому, что вы можете сделать, если хотите.

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
}

И это значит, что[1, 2, 3, 4]Если вы хотите, чтобы каждый из этих чисел сложился вместе.tradesКаждый транзакционный запись в матрице содержит данные, в которых суммируется количество транзакций.self.vol = 0.7 * self.vol + 0.3 * _.reduce(...)Позвольте мне использовать...Это не так уж сложно увидеть, как это работает.self.volУровень, который используется для расчета, также является средним, т.е. 30% от общего объема сделок, сделанных в последнее время, и 70% от объема сделок, сделанных в последнее время. Этот показатель устанавливается авторами стратегии, и, возможно, связан с наблюдением рынка. Если вы спрашиваете меня, что делать, если интерфейс, получающий данные о недавних сделках, возвращает мне повторяющиеся старые данные, то я получаю ошибочные данные, но есть ли смысл использовать их?

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

Это определение может быть основано на определении ID сделки в записи сделки, а накопление может быть вызвано только тогда, когда ID больше, чем ID, записанное в прошлый раз, или если интерфейс биржи не предоставляет ID.trade.Id == 0В данном случае, если вы хотите, чтобы ваш бизнес был успешным, вы можете использовать время в записи сделок, чтобы определить, когда это произойдет.self.lastTradeIdВ данном случае мы храним время записи сделки, а не идентификатор.

Вторая добавленная функция:

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

Посмотрите дальше.updateOrderBookФункция, как видно из буквального значения названия функции, выполняет функцию обновления заказа.GetDepth()Получить данные о текущих рыночных заказах (продать один... продать n, купить один... купить n) и записывать данные о заказах вself.orderBookСреди. В дальнейшем, если заказать дешевые данные покупки или продажи, меньше чем в 3 раундах, функция недействительна.

После этого были просчитаны два показателя:

  • Расчет стоимости заказа При расчете цены проката также используется среднее значение, для расчета оплаты, право на покупку является более значительным - 61.8% ((0.618), продажа - 38.2% ((0.382)). При расчете цены продажи и выкупа, однако, права на продажу и выкуп значительнее. Почему 0.618, возможно, автор предпочитает золотое разделение. Что касается последнего плюс минус один пункт цены ((0.01) для того, чтобы немного отклониться от прямого центра расписания.

  • Обновление временной последовательности заказа в первых трех слоях с средней ценой Для первых трёх классов покупки, продажи и цены на товары делают средневзвешенный расчет, вес первого класса 0.7, вес второго класса 0.2, вес третьего класса 0.1. Мы рассмотрим следующие цифры:

    (买一 + 卖一) * 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
    

    Здесь можно увидеть, что цена, которая в конечном итоге рассчитана, на самом деле является ценной позицией трех средних классов, которые торгуются на рынке в настоящее время. Затем используйте эту вычисленную цену, чтобы обновитьself.pricesМассив, выбирающий самый старый данный (((shift()Функция), обновляемая в новейшие данные ((посредствомpush()Функции, Shift, Push - это методы, которые используются для создания JS-функций.self.pricesМассив - это поток данных с временной последовательностью.

Я хочу, чтобы вы сказали мне, что я не хочу кашлять, я хочу пить воду, я хочу, чтобы вы пришли сюда, чтобы сделать анатомию, и я хочу, чтобы вы пришли сюда, и я хочу, чтобы вы пришли сюда, и я хочу, чтобы вы пришли сюда, и я хочу, чтобы вы пришли сюда.


Больше

Постепенно становится сильнееДобрый день, хотелось бы спросить. self.prices заранее заполнить 15 исторических цен на сделки, а затем заполнить первые три разряда с средней ценой.

СнлппЯ хочу похвалить мечту.

m0606К сожалению, многие биржевые трейдеры сократили свои позиции до одного тика, что делает эту стратегию бессмысленной, пытаясь встроить операцию "купи-продай-продай".

Мама.Спасибо, я написал версию python, которая запустилась на монете, и это была настоящая заработка. 20 ножей исчезли менее чем за 5 минут.

БвксяокЭто потрясающе, я не могу полностью понять без объяснения снов, спасибо за терпение и объяснение!

Эдди.Золото делится на 0.618 0.382 используется Фибо Суммарная партия коров

Смотрите.Да, коровьи скоты.

Эван1987Спасибо за подробный ответ.

Сделай что-нибудь.Пытаюсь.

- Да, конечно."Семьдесят лет назад я был в тюрьме. По словам одного из авторов статьи, "это очень сложный вопрос, но он выглядит очень сложно".

Девять солнцДрем-сум, коровы-боты!

Изобретатели количественного измерения - мечтыДа, это так.

Изобретатели количественного измерения - мечтыВ основном, это обучение мыслям и понимание высокочастотных торговых возможностей.

Изобретатели количественного измерения - мечтыВ статье, посвященной анализу принципов стратегии, написанной Травоном, говорится, что высокочастотные стратегии нуждаются в некоторой поддержке.

Изобретатели количественного измерения - мечтыСпасибо за поддержку. Если вам понравилось, помогите поделиться.

Изобретатели количественного измерения - мечтыСпасибо за поддержку!

Изобретатели количественного измерения - мечтыСпасибо за поддержку!

Изобретатели количественного измерения - мечтыСпасибо за поддержку!

Изобретатели количественного измерения - мечтыКогда я учился в школе, я особенно хорошо помню этот золотой пропорцион, и я сказал, что это самый красивый прямоугольник в таком пропорции.

Изобретатели количественного измерения - мечтыСпасибо за поддержку.

Изобретатели количественного измерения - мечтыНа самом деле не сложно, сравнение в этом примечании довольно сложное, строка за строкой описывается как можно проще.