이 전략은 OKCoin, Binance, Bitget 등과 같은 여러 선물 플랫폼에서 펀딩 비율을 얻고 모니터링하는 데 사용됩니다. 평행 스레드를 통해 다양한 거래소의 영구 계약 시장을 조사하고 요청 빈도를 최적화하기 위해 지연 메커니즘을 사용하여 펀딩 비율 데이터를 얻습니다.
이 문서에서는 디스플레이 및 펀딩 레이트 알람 푸시 기능을 지원하기 위해 전략에 몇 가지 변경 사항을 수행합니다.
오픈 소스 주소:https://www.fmz.com/strategy/470345
플랫폼 목록, 기호 목록 및 투표 간격을 필요에 따라 특정 거래 요구를 충족시킬 수 있습니다.
시나리오는 몇 가지 주요 부분으로 나뉘어 있습니다:
// Start the funding rate monitoring thread and create a separate thread for each exchange's funding rate data
function startFundingWorker() {
exchanges.forEach((_, pos) => {
__Thread(function (pos) {
let e = exchanges[pos]
let eName = e.GetName()
// Set request delays for different exchanges to prevent frequent requests from causing throttling
let delaySettings = {
'Futures_OKCoin': 20,
'Futures_Binance': 500,
'Futures_MEXC': 100,
}
// Need to traverse the list of exchange names for all markets, these exchanges do not support getting all trading pairs at once
let needInterate = ['Futures_OKCoin', 'Futures_Bitget','Futures_OKX', 'Futures_KuCoin', 'Futures_MEXC']
// Set delay based on exchange name
let delay = function () {
let n = delaySettings[eName]
if (n) {
Sleep(n)
}
}
// Set the update interval to update every two minutes
let epoch = 60000 * 2;
let ts = 0;
let fundings = {}
// Infinite loop, get funding rate at fixed intervals
while (true) {
let now = new Date().getTime()
if (now - ts < epoch) {
// If the update cycle is not reached, pause for 1 second and then continue checking
Sleep(1000)
continue
}
let markets = e.GetMarkets()
if (!markets) {
// If market information cannot be obtained, try again after a delay
Sleep(1000)
continue
}
// If the exchange is in the list that needs to be traversed, request the funding rate for each market
if (needInterate.includes(eName)) {
for (let symbol in markets) {
if (symbol.includes('.swap') && symbol.includes('_USDT')) {
let ret = e.GetFundings(symbol)
if (ret) {
for (let r of ret) {
fundings[r.Symbol] = r
}
}
delay();
}
}
} else {
// For exchanges not in the traversal list, only request the funding rate of USDT.swap
let ret = e.GetFundings('USDT.swap')
if (ret) {
for (let r of ret) {
fundings[r.Symbol] = r
}
}
}
// Update data timestamp
ts = now
// Stores the exchange's funding rate data
__threadSetData(0, eName+"_funding", fundings)
}
}, pos)
})
}
// Get the funding rate data of the specified exchange
function getFundings(eName) {
let efundings = __threadGetData(0, eName+"_funding")
if (!efundings) {
return null
}
return efundings
}
// Update the funding rate table and display it in the log
function UpdateStatus(){
let table = {
type: 'table',
title: 'Funding Rate%',
cols: ['index', 'symbol'], // Initialization column, containing symbol
rows: []
};
let fundingRates = {};
exchanges.forEach((e) => {
let eName = e.GetName();
if (fundings[eName]) {
for (let symbol in fundings[eName]) {
// Parse short symbol names and remove unnecessary prefixes
let short_symbol = symbol.split('_')[0].replace(/^(100|1000|10000|100000|1000000|10000000)|^(100|1000|10000|100000|1000000|10000000)$/g, '');
let rate = fundings[eName][symbol].Rate;
let day = 24 / (fundings[eName][symbol].Interval / 3600000)
// Initialize symbol data structure
if (!fundingRates[short_symbol]) {
fundingRates[short_symbol] = { total: 0, count: 0, day_rate: {}, next_time: {}, last_time:0};
}
// Record and push rates that exceed the threshold
if (Math.abs(rate) > 0.01 && Date.now() - fundingRates[short_symbol].last_time > 30*60*1000) {
Log(e.GetName(), symbol, rate, '@')
fundingRates[short_symbol].last_time = Date.now()
}
fundingRates[short_symbol].total += rate;
fundingRates[short_symbol].count++;
fundingRates[short_symbol].day_rate[eName] = _N(rate * day , 6); // Record rates
fundingRates[short_symbol].next_time[eName] = _N((fundings[eName][symbol].Time - Date.now()) / 3600000 , 1) + 'h'
}
}
});
// Added rate columns and next update time columns for each exchange
for (let e of exchanges) {
table.cols.push(e.GetName()+' Rate');
table.cols.push('Next Time');
}
table.cols.push('Average Rate'); // Add an average rate column
let i = 0;
// Iterate over each symbol and fill in the data
for (let symbol in fundingRates) {
let data = fundingRates[symbol];
if (data.count == 1) {
continue // Symbols containing only a single data point are ignored
}
let averageRate = data.total / data.count; // Calculate average rate
let row = [i++, symbol];
for (let e of exchanges) {
row.push(data.day_rate[e.GetName()] || null); // Filling the fees of various exchanges
row.push(data.next_time[e.GetName()] || null);
}
row.push(_N(averageRate, 6)); // Filling average rate
table.rows.push(row);
}
LogStatus('`' + JSON.stringify(table) + '`');
}
// Main function, start funding rate monitoring and status update
var fundings = {}
function main() {
startFundingWorker() // Start monitoring threads for each exchange
while (true) {
exchanges.forEach((e) => {
let eName = e.GetName()
let eFundings = getFundings(eName)
fundings[eName] = eFundings
})
Sleep(15000) // Update every 15 seconds
UpdateStatus()
}
}