마지막 장의 내용을 계속 설명해 보겠습니다 (https://www.fmz.com/bbs-topic/9725).
세 번째 추가 기능:
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 ( \"\" Start Balance \"\", 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 ( \"\" Start Balance \"\", 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
그리고 함수를 호출exchange.GetAccount
FMZ API 인터페이스에서. 현금 계좌의 최신 데이터를 얻고 변수에 할당account
그 다음 변수를 판단account
만약 변수가null
(예를 들어, 타임 아웃, 네트워크, 교환 인터페이스 예외, 등)if (!account) {...}
) 직접적으로.
self.account = account
로컬 변수를 할당하는 것입니다account
에 대한account
구성된 객체의 속성으로 구성된 객체에 최신 계정 정보를 기록합니다.
Var now = new Date().getTime ()
로컬 변수를 선언합니다now
그리고 소환합니다getTime()
자바스크립트 언어now
.
if (self.orderBook.Bids.length > 0 && now - self.preCalc > (CalcNetInterval * 1000)){...}
현재 시간표와 마지막으로 기록된 시간표 사이의 차이가 매개 변수를 초과하는 경우CalcNet Interval * 1000
, 그것은 마지막 시간에서 업데이트되었다는 것을 의미합니다. 지금까지, 그것은 초과했습니다CalcNetInterval * 1000
밀리초 (CalcNetInterval
2초) 로 정규 시간에 인쇄 수입의 기능을 실현합니다. 하나를 구입하는 가격이 수입을 계산하는 데 사용되기 때문에,self.orderBook.Bids.length > 0
또한 조건에서 정의됩니다 (depth data, 순서 목록에 유효한 레벨 정보가 있어야합니다). 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
true 이면,self.preNet
변수와 함께 순액을 기록하는 데 사용됩니다.net
. 그 다음 누적 총 인쇄net
FMZ 퀀트 트레이딩 플랫폼 로봇의 수익률 곡선 차트에LogProfit
FMZ API 문서에서 쿼리 할 수 있습니다.)
정기적 인 수익 인쇄가 시작되지 않으면 다음 프로세스를 계속하여 수익을 기록하십시오.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으로 증가 할 때마다 세 개의 작은 주문이 배치됩니다. 마찬가지로, 화폐 잔액은self.p > 0.52
, 더 많은 화폐가 있다면, 하나를 판매하고 작은 주문을 풀어. 마지막으로, 모든 주문을 취소Sleep(BalanceTimeout)
파라미터 설정에 따라 일정 시간 동안.
Var orders = exchange. Get Orders () # Get all current makers, with orders variable
If (orders) { # If the variable orders used to obtain the current order data is not null
for (var i = 0; i < orders.length; I + +) { # Loop through orders and cancel orders one by one
if (orders[i].Id != self.tradeOrderId) {
Exchange. CancelOrder (orders [I]. Id) # Call exchange. CancelOrder to cancel orders based on orders [I]. Id
}
}
}
네 번째 추가 기능:
전략의 핵심 부분에서, 여기가 주요 플레이입니다.self.poll = function(){...}
이 전략의 주요 논리는 우리의 역할입니다.main()
함수는 실행을 시작하고 무한대로 들어가게 됩니다.while
루프, 우리는 사용var reaper = LeeksReaper()
leeksreaper 객체를 구성하고, 그 다음 루프 호출을 실행reaper.poll()
에main()
function.
이self.poll
함수가 실행되기 시작하여 각 루프 전에 준비 작업을 수행합니다.self.numTick++
수를 증가시킵니다.self.updateTrades()
최근 시장 거래 기록을 업데이트하고 관련 사용 데이터를 계산합니다.self.updateOrderBook()
주문 데이터를 업데이트하고 관련 데이터를 계산합니다.self.balanceAccount()
현금 (상위) 잔액을 확인합니다.
Var burstPrice = self. Prices [self. Prices. Length-1] * BurstThresholdPct # Calculate Burst Price
Var bull = false # Declare a bull-marked variable, initially false
Var bear = false # Declare a bear marked variable, initially false
Var tradeAmount = 0 # Declare the transaction amount variable, initially 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)) // it will intercept the elements from 4 to 1 and return a new array: [4,3,2,1]
}
곰 시장이나 황금 시장을 판단하는 조건은 다음과 같습니다.
·self.numTick > 2
즉, 새로운 탐지 라운드가 시작될 때, 적어도 세 번의 탐지 라운드를 거쳐 발사되어야 하며, 처음부터 발사되는 것을 피해야 합니다.
· 최근 데이터의 차이self.prices
가격 순서, 즉 최신 데이터와 이전 범위의 최대 또는 최소 가격self.prices
배열이 폭발 가격을 초과해야 합니다burstPrice
.
모든 조건이 사실이라면, 표시bull
또는bear
true로 표시하고 변수에 값을 부여합니다tradeAmount
스타드 거래를 계획하기 위해서요
그 다음,self.vol
이전에서 업데이트 및 계산self.updateTrades()
기능,BurstThresholdVol
이 매개 변수는 트랜잭션 강도를 줄이느냐 (계획된 트랜잭션 부피를 줄이느냐) 를 결정한다.
if (self.vol < BurstThresholdVol) {
TradeAmount * = self. Vol/BurstThresholdVol //Reduce the planned volume by self. Vol/BurstThresholdVol times of the previous volume
}
if (self.numTick < 5) {
TradeAmount * = 0.8 // reduced to 80% of the plan
}
If (self. NumTick < 10) { // reduce to 80% of the plan
tradeAmount *= 0.8
}
다음으로 거래 신호와 볼륨이 요구 사항을 충족하는지 판단합니다.
If ( (!Bull && !Bear) | | tradeAmount < MinStock) { # If it is not a bull market and not a bear market, or the amount tradeAmount planned to trade is less than the minimum trading volume MinStock set by the parameter, the poll function returns without trading operations directly
return
}
위 판결 후, 집행var tradePrice = bull ? self.bidPrice: self.askPrice
거래가격은 하향시장인지 올시장인지에 따라 정하고 해당 화물표가격과 함께 값을 부여합니다.
마지막으로,while
루프가 입력되고, 루프의 유일한 중지 조건은 계획된 거래량이tradeAmount > = MinStock
최소 거래량보다 낮습니다.
루프에서, 주문은 현재 시장 상태에 따라 실행됩니다. 그리고 변수에 주문 ID를 기록orderId
. Sleep(200)
각 루프에 순서를 넣은 후 200 밀리초를 기다립니다. 루프는orderId
true 입니다. (오더가 실패하면 오더 ID는 반환되지 않으며, if 조건은 트리거되지 않습니다.)self.tradeOrderId
.
변수를 선언합니다order
오더 데이터를 저장하는 데 사용되며 초기 값은null
. 그러면 ID의 순서 데이터는 루프에서 얻으며, 주문이 메이커 상태인지 판단하면, ID의 순서가 취소되고, 그렇지 않으면 탐지 루프는 종료됩니다.
Var order = null // Declare a variable to hold the order data
While (true) { // a while loop
Order = exchange. GetOrder (orderId) // Call GetOrder to query the order data whose order ID is orderId
If (order) { // If the order data is queried and the query fails and the order is null, the current if condition will not be triggered
If (order. Status = = ORDER _ STATE _ PENDING) { // Judge whether the order status is maker
Exchange. CancelOrder (orderId) // If the order is maker, cancel the order
Sleep(200)
} else { // otherwise execute break to end the current while loop
break
}
}
}
다음 절차를 수행합니다.
Self. TradeOrderId = 0 // Reset self. TradeOrderId.
TradeAmount-= order. DealAmount // Update tradeAmount, subtract the quantity of the order on the bill of lading that has been completed
TradeAmount * = 0.9 //Decrease the order amount
If (order. Status = = ORDER _ STATE _ CANCELED) { // if the order is already cancelled
Self. UpdateOrderBook () // Update data such as order book
While (bull & & self. BidPrice-tradePrice > 0.1) { // In a bull market, if the updated bill of lading price exceeds the current trading price by 0.1, the trading amount will be reduced and the trading price will be adjusted slightly
tradeAmount *= 0.99
tradePrice += 0.1
}
While (bear & & self. AskPrice-tradePrice < -0.1) { // In a bear market, if the updated bill of lading price exceeds the current trading price by 0.1, the trading amount will be reduced and the trading price will be adjusted slightly
tradeAmount *= 0.99
tradePrice -= 0.1
}
}
프로그램 프로세스가 종료되면while (tradeAmount > = MinStock){...}
, 이 가격 폭발 거래 프로세스의 실행이 완료되었다는 것을 나타냅니다.
실행self.numTick = 0
, 즉, 다시 설정self.numTick
0으로
이LeeksReaper()
생성자는self
실행이 끝나면, 즉,var reaper = LeeksReaper()
, 그것은 반환됩니다reaper
.
현재까지 우리는LeeksReaper()
이 컨스트럭터는 리크스 리퍼 객체, 리크스 리퍼 객체의 각 메소드, 그리고 주요 논리 함수의 실행 과정을 구성합니다. 이 기사를 읽은 후에 이 고주파 전략 알고리즘 프로세스에 대한 명확한 이해가 있을 것이라고 믿습니다.