리소스 로딩... 로딩...

양배추 재배기 전략 해부 (1)

저자:발명가들의 수량화 - 작은 꿈, 2020-11-12 22:11:32, 업데이트: 2024-12-06 22:20:54

img

콩나뭇가지 재배기 전략 분석

최근 발명가 양적화 微信 그룹 토론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이 함수에서, 이 함수에서, 이 함수에서, 이 함수에서, 이 함수에서, 이 함수에서, 이 함수에서, 이 함수에서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이 비율은 전략 작성자가 직접 설정한 것으로 시장 법칙을 관찰하는 것과 관련이 있을 수 있다. 만약 여러분이 제게 물어본다면, 만약 제가 최근에 거래된 데이터를 가져온 인터페이스가 제게 반복된 오래된 데이터를 돌려주면, 제가 얻은 데이터는 틀렸으며, 또 유용할 수 있을까요?

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

이 판단은 트랜잭션 기록의 트랜잭션 ID를 기준으로 판단할 수 있으며, ID가 이전 기록의 ID보다 크면만 누적을 유발하거나, 거래소 인터페이스가 ID를 제공하지 않으면, 즉,trade.Id == 0거래 기록의 시간표를 사용하여,self.lastTradeId트랜잭션 기록의 ID가 아닌 시간표가 저장됩니다.

두 번째 추가 함수:

    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()현재 시장 주문 얇은 데이터를 얻습니다 (팔기 1... 팔기 n, 구매 1... 구매 n)self.orderBook중. 다음으로, 주문 얇은 데이터 구매, 판매 주문 3 개 미만인 경우 무효 함수를 직접 반환합니다.

그 후 두 가지 자료를 계산했습니다.

  • 요금 요금 계산 계산하는 청구서 가격은 또한 중량화 된 평균을 사용하여 계산됩니다. 지불금을 계산 할 때 구매 권리는 61.8% ((0.618), 판매 권리는 나머지 무게 38.2% ((0.382) 를 차지합니다. 송수신 판매 가격 계산에 있어서도 마찬가지이며, 판매권과 판매권에 비해 가격권이 더 크다. 0.618이 왜인지에 대해서는 저자가 금분할 비율을 선호하는 것일 수도 있다. 마지막에 추가한 점점값 (0.01) 을 빼는 것은 사서 중추에 조금 더 기울기 위해서다.

  • 업데이트 시간 순서에서 주문 얇은 상위 3 계열 중량 평균 가격 주문이 적은 첫 3단계 구매, 판매권 가격의 가중화 평균 계산, 1단계 중량 0.7, 2단계 중량 0.2, 3단계 중량 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
    

    여기서 볼 수 있듯이, 최종 계산된 가격은 실제로 반현실 시장에서 상장된 3단계 중간에 있는 가격 위치입니다. 그리고 그 계산된 가격으로,self.prices가장 오래된 데이터 (() 를 뽑아내기 위해shift()함수), 최신 데이터에 대한 업데이트를 통해push()함수, Shift, Push 함수는 JS 언어의 수직 객체의 방법이며, JS 자료를 검색하여 생성할 수 있습니다.)self.prices대수열은 시간 순서 순서로 이루어진 데이터 스트림이다.

기침, 목수, 해부, 여기까지, 다음 시즌까지


더 많은

나라는 점점 더 강해지고 있습니다.안녕하세요, 질문하고 싶습니다.self.prices 먼저 15개의 역사 거래 가격을 채우고, 다음으로 주문을 발급하기 전에 세 개의 중인 평균 가격을 채우십시오.

저는 꿈에 대한 칭찬을 드리고 싶습니다.

m0606불행히도, 많은 거래소에서 거래자들은 매매를 한 번 구매 한 번 판매 한 번 판매 한 번 판매 한 번 판매 한 번 판매 한 번 구매 한 번 판매 한 번 판매 한 번 판매 한 번 판매 한 번 판매 한 번 판매 한 번 판매 한 번 판매 한 번 판매 한 번 판매 한 번 판매 한 번 판매 한 번 판매 한 번 판매 한 번 판매 한 번 판매 한 번 판매 한 번 판매 한 번 판매 한 번 판매 한 번 구매 한 번 판매 한 번 판매 한 번 판매 한 번 판매 한 번 판매 한 번 판매 한 번 판매 한 번 판매 한 번 구매 한 번 판매 한 번 판매 한 번 판매 한 번 판매 한 번 판매 한 번 판매 한 번 판매 한 번 판매 한 번 판매 한 번 판매 한 번 구매 한 번 판매 한 번 판매 한 번 판매 한 번 판매 한 번 판매 한 번 판매 한 번 판매 한 번 판매 한 번 판매 한 번 판매 한 번 판매 한 번 판매 한 번 판매 한 번 판매 한 번 판매 한 번 판매 한 번 판매 한 번 판매 한 번 판매 한 번 판매 한 번 판매 한 번 판매 한 번 판매 한 번 판매 한 번 판매 한 번 판매 한 번 판매 한 번 판매 한 번 판매 한 번 판매 한 번 판매 한 번 판매 한 번

엄마감사합니다, 저는 파이썬 버전을 티코인에서 실행했습니다. 20개의 칼이 5분 이내에 사라졌습니다.

정말 멋져요, 꿈의 전체적인 설명이 없어도 완전히 이해할 수 없습니다.

에디금분해 0.618 0.382는 사용된 피보 꿈의 총 소 떼

정말 많은 소들이 있습니다.

에반1987이 질문에 대한 답변은 매우 흥미롭습니다.

어서꿈의 총 소 p

꿈의 총, 소의 덩어리! 이 글은 글자 그대로이지만, 매우 복잡해 보입니다.

9개의 태양꿈의 총, 소의 덩어리!

발명가들의 수량화 - 작은 꿈네, 그렇습니다.

발명가들의 수량화 - 작은 꿈이 모든 것은 주로 아이디어를 배우고, 이러한 높은 빈도의 거래 기회를 통찰하는 것입니다.

발명가들의 수량화 - 작은 꿈이 글은 라스본이 쓴 전략의 원리 분석에 대한 글을 읽을 수 있습니다. 높은 빈도 전략은 약간의 지원이 필요합니다.

발명가들의 수량화 - 작은 꿈감사합니다. 좋아하면 공유해 주세요.

발명가들의 수량화 - 작은 꿈감사합니다!

발명가들의 수량화 - 작은 꿈감사합니다!

발명가들의 수량화 - 작은 꿈감사합니다!

발명가들의 수량화 - 작은 꿈학창시절, 이 황금분할 비율을 배웠을 때 특히 잘 기억하고, 이 비율이 가장 아름다운 길고 넓은 정사각형이라고 말했다~~하지만 왜인지 모르겠습니다.

발명가들의 수량화 - 작은 꿈감사합니다.

발명가들의 수량화 - 작은 꿈사실 복잡하지 않습니다. 이 설명의 비교는 복잡합니다. 문장별로 가능한 한 이해하기 쉽게 설명합니다.