حال ہی میں ، اس کے بارے میں ایک گرم بحث ہو رہی ہےprint money
ایف ایم زیڈ کوانٹ وی چیٹ گروپ میں روبوٹ۔ ایک بہت پرانی حکمت عملی کوانٹس کی آنکھوں میں پھر سے داخل ہوئی ہے۔ لیکس ریپر۔
روبوٹ ٹریڈنگ کا اصولprint money
میں نے اپنے آپ کو اس بات کا الزام عائد کیا کہ میں نے اس وقت لیکس ریپر کی حکمت عملی کو زیادہ نہیں پڑھا اور اسے اچھی طرح سے نہیں سمجھا۔ لہذا ، میں نے اصل حکمت عملی کو ایک بار پھر احتیاط سے پڑھا اور ایف ایم زیڈ کوانٹ پر ٹرانسپلانٹ شدہ او کے کوئن لیکس ریپر کے ٹرانسپلانٹ شدہ ورژن کو دیکھا۔
ایف ایم زیڈ کوانٹ پلیٹ فارم پر مبنی ٹرانسپلانٹڈ لیکس ریپر کی حکمت عملی کا تجزیہ کیا جاتا ہے۔ تاکہ پلیٹ فارم کے صارفین اس حکمت عملی کے خیال کو سیکھ سکیں۔
اس مضمون میں ، ہم پروگرامنگ سے متعلق بورنگ مواد کو کم سے کم کرنے کے لئے حکمت عملی کے خیال اور ارادے کے پہلوؤں سے مزید تجزیہ کریں گے۔
[ٹرانسپلانٹنگ OKCoin LeeksReaper] حکمت عملی کا ماخذ کوڈ:
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("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)
}
}
}
}
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 حکمت عملی منطق ماڈیول (ایک اعتراض) کے constructor کے طور پر سمجھا جا سکتا ہے. مختصر میں،LeeksReaper()
ایک لیس ریپر ٹریڈنگ منطق کی تعمیر کے لئے ذمہ دار ہے.
کلیدی الفاظ:
· حکمت عملی کی پہلی لائنmain
فنکشن:var reaper = LeeksReaper()
، کوڈ ایک مقامی متغیر کا اعلان کرتا ہےreaper
اور پھر ایک حکمت عملی منطق اعتراض ہے کہ ایک قدر تفویض کی تعمیر کے لئے LeeksReaper() تقریب بلاتا ہےreaper
.
حکمت عملی کا اگلا قدمmain
فنکشن:
while (true) {
reaper.poll()
Sleep(TickInterval)
}
درج کریںwhile
لامتناہی لوپ اور عملدرآمد کی تقریب کو چلانے کے رکھنےpoll()
کےreaper
اعتراض،poll()
فنکشن بالکل جہاں ٹریڈنگ کی حکمت عملی کا بنیادی منطق جھوٹ ہے اور پوری حکمت عملی پروگرام بار بار ٹریڈنگ منطق کو انجام دینے کے لئے شروع ہوتا ہے.
اور لائن کے بارے میںSleep(TickInterval)
، یہ سمجھنے میں آسان ہے، یہ ٹریڈنگ منطق کی گردش کی تعدد کو کنٹرول کرنے کے مقصد کے ساتھ، مجموعی طور پر ٹریڈنگ منطق کے ہر عمل کے بعد توقف کے وقت کو کنٹرول کرنے کے لئے ہے.
LeeksReaper()
تعمیر کاردیکھو کہ کس طرحLeeksReaper()
فنکشن ایک حکمت عملی منطقی اعتراض کی تعمیر کرتا ہے.
کےLeeksReaper()
فنکشن خالی چیز کا اعلان کرکے شروع ہوتا ہے،var self = {}
، اور عملدرآمد کے دورانLeeksReaper()
تقریب آہستہ آہستہ اس خالی شے کے لئے کچھ طریقوں اور صفات کا اضافہ کریں گے، آخر میں اس شے کی تعمیر مکمل کرنے اور اسے واپس (یعنی، قدم کےmain()
کے اندر کامvar reaper = LeeksReaper()
، لوٹایا اعتراض کے لئے تفویض کیا جاتا ہےreaper
).
صفات کو شامل کریںself
چیز
اگلا، میں نے بہت سے صفات کو شامل کیاself
. میں مندرجہ ذیل کے طور پر ہر ایک وصف کی وضاحت کریں گے، جو ان صفات اور متغیرات کے مقصد اور نیت کو تیزی سے سمجھ سکتے ہیں، حکمت عملی کی تفہیم کو آسان بنانے، اور کوڈ کو دیکھنے پر الجھن سے بچنے کے.
self.numTick = 0 # It is used to record the number of transactions not triggered when the poll function is called. When the order is triggered and the order logic is executed, self.numTick is reset to 0
self.lastTradeId = 0 # The transaction record ID of the order that has been transacted in the transaction market. This variable records the current transaction record ID of the market
self.vol = 0 # Reference to the trading volume of each market inspection after weighted average calculation (market data is obtained once per loop, which can be interpreted as a time of market inspection)
self.askPrice = 0 # The bill of lading price of the sales order can be understood as the price of the listing order after the strategy is calculated
self.bidPrice = 0 # Purchase order bill of lading price
self.orderBook = {Asks:[], Bids:[]} # Record the currently obtained order book data, that is, depth data (sell one... sell n, buy one... buy n)
self.prices = [] # An array that records the prices on the time series after the calculation of the first three weighted averages in the order book, which means that each time the first three weighted averages of the order book are stored, they are placed in an array and used as a reference for subsequent strategy trading signals, so the variable name is prices, in plural form, indicating a set of prices
self.tradeOrderId = 0 # Record the order ID after the current bill of lading is placed
self.p = 0.5 # Position proportion: when the value of currency accounts for exactly half of the total asset value, the value is 0.5, that is, the equilibrium state
self.account = null # Record the account asset data, which is returned by the GetAccount() function
self.preCalc = 0 # Record the timestamp of the last time when the revenue was calculated, in milliseconds, to control the frequency of triggering the execution of the revenue calculation code
self.preNet = 0 # Record current return values
خود کو ان صفات کو شامل کرنے کے بعد، میں طریقوں کو شامل کرنے کے لئے شروعself
اعتراض تاکہ یہ اعتراض کچھ کام کر سکتا ہے اور کچھ افعال ہیں.
پہلا فنکشن نے مزید کہا:
self.updateTrades = function() {
var trades = _C(exchange.GetTrades) # Call the FMZ encapsulated interface GetTrades to obtain the latest market transaction data
if (self.prices.length == 0) { # When self.prices.length == 0, the self.prices array needs to be filled with numeric values, which will be triggered only when the strategy starts running
while (trades.length == 0) { # If there is no recent transaction record in the market, the while loop will keep executing until the latest transaction data is available and update the trades variable
trades = trades.concat(_C(exchange.GetTrades)) # concat is a method of JS array type, which is used to concatenate two arrays, here is to concatenate the "trades" array and the array data returned by "_C(exchange.GetTrades)" into one array
}
for (var i = 0; i < 15; i++) { # Fill in data to self.prices, and fill in 15 pieces of latest transaction prices
self.prices[i] = trades[trades.length - 1].Price
}
}
self.vol = 0.7 * self.vol + 0.3 * _.reduce(trades, function(mem, trade) { # _. Reduce function is used for iterative calculation to accumulate the amount of the latest transaction records
// 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 ڈیٹا لنک (https://underscorejs.net/#reduce)
مطلب بھی بہت آسان ہے، مثال کے طور پر:
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)) {
...
}
فیصلہ۔ اس کا فیصلہ ٹرانزیکشن ریکارڈ میں ٹرانزیکشن آئی ڈی کی بنیاد پر کیا جاسکتا ہے۔ مجموعہ صرف اس وقت شروع ہوتا ہے جب آئی ڈی آخری ریکارڈ کی آئی ڈی سے زیادہ ہو یا اگر ایکسچینج انٹرفیس آئی ڈی فراہم نہیں کرتا ہے ، یعنی ،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
فنکشن کے نام سے ، ہم دیکھ سکتے ہیں کہ اس کا استعمال آرڈر بک کو اپ ڈیٹ کرنے کے لئے کیا جاتا ہے۔ تاہم ، یہ صرف آرڈر بک کو اپ ڈیٹ نہیں کرتا ہے۔ فنکشن FMZ API فنکشن کو کال کرنا شروع کرتا ہے۔GetDepth()
موجودہ مارکیٹ آرڈر بک کے اعداد و شمار حاصل کرنے کے لئے (ایک فروخت... فروخت ن ، ایک خریدنے... خریدنے ن) ، اور میں آرڈر بک کے اعداد و شمار کو ریکارڈself.orderBook
اگلا، فیصلہ اگر آرڈر بک کے اعداد و شمار کی خریداری کے حکم اور فروخت کے حکم 3 سے کم ہیں، اگر ایسا ہے تو، غلط تقریب براہ راست واپس آ جائے گا.
اس کے بعد، دو اعداد و شمار کا حساب لگایا جاتا ہے:
· نوٹس آف کنسائنمنٹ کی قیمت کا حساب لگائیں سامان کی فہرست کی قیمت کا حساب بھی وزن شدہ اوسط طریقہ کار کا استعمال کرتے ہوئے کیا جاتا ہے۔ خریداری کے آرڈر کا حساب لگاتے وقت ، لین دین کی قیمت سے قریب ترین خریداری کی قیمت کو 61.8٪ (0.618) اور لین دین کی قیمت سے قریب ترین فروخت کی قیمت کو دیا جانے والا وزن 38.2٪ (0.382) ہے لیز کی قیمت کا حساب لگاتے وقت ، لین دین کی قیمت کے قریب فروخت کی قیمت کو بھی وہی وزن دیا جاتا ہے۔ کیوں 0.618 ہے ، اس کے بارے میں ، یہ ہوسکتا ہے کہ مصنف سنہری حصے کے تناسب کو ترجیح دیتا ہے۔ آخری قیمت (0.01) کے بارے میں ، یہ افتتاحی مرکز کی طرف تھوڑا سا آفسیٹ کرنا ہے۔
· ٹائم سیریز پر آرڈر بک کی پہلی تین سطحوں کی وزن شدہ اوسط قیمت کو اپ ڈیٹ کریں
آرڈر بک میں خریداری اور فروخت کے آرڈر کی قیمتوں کی پہلی تین سطحوں کے لئے ، وزن شدہ اوسط کا حساب لگایا جاتا ہے۔ پہلی سطح کا وزن 0.7 ہے ، دوسری سطح کا وزن 0.2 ہے ، اور تیسری سطح کا وزن 0.1 ہے۔ کوئی کہہ سکتا ہے ،
(Buy one+Sell one) * 0.35+(Buy two+Sell two) * 0.1+(Buy three+Sell three) * 0.05
->
(Buy one+sell one)/2 * 2 * 0.35+(Buy two+sell two)/2 * 2 * 0.1+(Buy three+sell three)/2 * 2 * 0.05
->
(Buy one+sell one)/2 * 0.7+(Buy two+sell two)/2 * 0.2+(Buy three+sell three)/2 * 0.1
->
Average price of the first level * 0.7+average price of the second level * 0.2+average price of the third level * 0.1
جیسا کہ ہم یہاں دیکھ سکتے ہیں، حتمی حساب قیمت اصل میں موجودہ مارکیٹ میں تیسری افتتاحی کے وسط کی قیمت کی پوزیشن کا جواب ہے.
پھر صف کو اپ ڈیٹ کرنے کے لئے اس حساب قیمت کا استعمال کریںself.prices
، سب سے پرانی اعداد و شمار میں سے ایک کو باہر نکالنے (کے ذریعےshift()
فنکشن) اور اس میں تازہ ترین اعداد و شمار میں سے ایک کو اپ ڈیٹ کر رہا ہے ((کے ذریعےpush()
تقریب، شفٹ اور دھکا افعال JS زبان صف اعتراض کے طریقوں ہیں، آپ تفصیلات کے لئے JS ڈیٹا کی جانچ پڑتال کر سکتے ہیں). اس طرح صف تشکیلself.prices
، جو کہ وقت کی سیریز کے حکم کے ساتھ ڈیٹا کا ایک سلسلہ ہے.
تو چلو یہاں آرام کرتے ہیں، اور ہم آپ کو اگلے شمارہ میں دیکھیں گے ~