A estratégia de comércio de redes
(www.fmz.com)
A ideia básica da negociação em rede é muito direta. Em vez de colocar um comércio, colocamos vários negócios formando um padrão de rede. Normalmente, estes são inseridos como ordens
O que é o comércio de redes e como funciona? A negociação em rede é um jogo sobre a volatilidade do mercado. Há duas razões pelas quais é favorecida pelos traders. A primeira é que não requer que você tenha uma previsão definitiva sobre a direção do mercado.
A segunda é que funciona bem em mercados voláteis, onde não há uma tendência clara. Estas condições são muito comuns nos mercados de divisas.
A negociação em grade é um tipo de negociação de análise técnica que se baseia no movimento dentro de padrões específicos de grade. A negociação em grade é popular na negociação de câmbio.
Grade pode personalizar a direção
Operação comercial básica: comprar primeiro e depois vender.
A rede começará a enviar ordens de compra no preço que está abaixo do primeiro preço, que é o preço seguido pelo primeiro preço (segundo último preço de compra, terceiro último preço de compra...e assim por diante). Cada ordem de compra é separada pelo parâmetro
Após qualquer ordem de compra é concluída, o programa será com base no preço de compra, adicionar o preço do parâmetro
Vender em curto primeiro e depois comprar para cobrir: a operação é exatamente o oposto
O maior risco desta estratégia é quando a tendência do mercado é unilateral e as flutuações de preços excedem a grelha.
O código a seguir fez a grade com perda automática de parada e função de movimento.
Observações:
A estratégia usa um projeto de ordem pendente virtual, que fornece uma grande quantidade de processamento para a troca para limitar o número de ordens pendentes e resolve o problema de forma flexível.
A lógica da grade é flexível em design e inteligente em estrutura.
Cálculo de lucro e perda, cada algoritmo estatístico numérico pode ser usado como referência e cada projeto de detecção de condição é rigoroso. (para minimizar a possibilidade de BUG)
O código fonte vale muito a pena ser aprendido.
Para mais informações, consulte:
https://www.fmz.com/strategy/112633
Código de origem:
// Grid can customize direction
// Basic trading operation: buy first and then sell.
// The grid will start to send buying order at the price that below the first price, which is the price follow
// by the first price (second latest buying price, third latest buying price…and so on). Each buying order is separated by
// the "price interval" parameter. The number of pending orders is "single quantity", and will send the order total until
// the "total quantity" is filled.
// After any buying order is completed, the program will be on the basis of the buying price, add the price of the "price
// difference" parameter to the sell price, after the order has been sold, and then re-start the progress of this
// grid strategy (checking, place order, wait until it executed, sell)
// Selling short first and then buy to cover: the operation is just the opposite
// The biggest risk of this strategy is when the market trend is unilateral moving, and the price fluctuations are exceeding the grid.
// The following code has made the grid with automatic stop loss and movement function.
// Comments:
// The strategy uses a virtual pending order design, which provides a great deal of processing for the exchange to limit the number
// of pending orders, and solves the problem flexibly.
// The grid logic is flexible in design and clever in structure.
// Profit and loss calculation, each numerical statistical algorithm can be used for reference, and each condition detection design
// is rigorous. (for minimize the possibility of BUG)
// The source code is very worth learning.
// Source Code:
/* Interface parameters (shown as global variables in the code)
OpType Grid Direction Drop-down box (selected) Buy first then sell | Sell first then buy
FirstPriceAuto initial price automatic boolean (true/false) true
FirstPrice@!FirstPriceAuto initial price numerical (number) 100
AllNum total number numerical (number) 10
PriceGrid Price Interval numerical (number) 1
PriceDiff spread numerical (number) 2
AmountType order size drop-down box (selected) buy and sell the same amount | custom amount
AmountOnce@AmountType==0 Single transaction quantity numerical (number) 0.1
BAmountOnce@AmountType==1 Buying Order Size numerical (number) 0.1
SAmountOnce@AmountType==1 Selling order size numerical (number) 0.1
AmountCoefficient@AmountType==0 Quantity difference String (string) *1
AmountDot The decimal point numerical (number) 3
EnableProtectDiff Turn on spread protection Boolean (true/false) false
ProtectDiff@EnableProtectDiff Entry spread Price Protection numerical (number) 20
CancelAllWS stop cancels all pending orders Boolean (true/false) true
CheckInterval polling interval number numerical (number) 2000
Interval failure retry interval numerical (number) 1300
RestoreProfit restores last profit Boolean (true/false) false
LastProfit@RestoreProfit Last Profit numerical (number) 0
ProfitAsOrg@RestoreProfit Last profit counted as average price Boolean (true/false) false
EnableAccountCheck enable balance verification Boolean (true/false) true
EnableStopLoss@EnableAccountCheck open Stop Loss Boolean (true/false) false
StopLoss@EnableStopLoss maximum floating loss numerical (number) 100
StopLossMode@EnableStopLoss Post-stop loss operation Drop-down box (selected) Recycle and exit | Recycle and re-cast
EnableStopWin@EnableAccountCheck Turn on Take Profit Boolean (true/false) false
StopWin@EnableStopWin Maximum floating profit Number type (number) 120
StopWinMode@EnableStopWin post-take profit operation drop-down box (selected) Recycle and exit | Recycle and re-cast
AutoMove@EnableAccountCheck auto Move Boolean (true/false) false
MaxDistance@AutoMove maximum distance numerical (number) 20
MaxIdle@AutoMove maximum idle (seconds) numerical (number) 7200
EnableDynamic Turns on dynamic pending orders Boolean (true/false) false
DynamicMax@EnableDynamic order expiration distance Number (number) 30
ResetData clears all data at startup Boolean (true/false) true
Precision price decimal length numerical (number) 5
*/
function hasOrder(orders, orderId) { // Check if there is an order with order ID in parameter orders
for (var i = 0; i < orders.length; i++) { // Traverse orders to check if there are same ids, if there are then return true
if (orders[i].Id == orderId) {
return true;
}
}
return false; // All traversed, no trigger if means haven't found the order with the ID orderId, return false
}
function cancelPending() { // Cancel all pending order functions
var ret = false; // Set return success tag variable
while (true) { // while loop
if (ret) { // If ret is true then Sleep for a certain time
Sleep(Interval);
}
var orders = _C(exchange.GetOrders); // Call the API to get the order information that the exchange did not executed.
if (orders.length == 0) { // If an empty array is returned, the exchange has no unexecuted orders.
break; // Jump out of the while loop
}
for (var j = 0; j < orders.length; j++) { // Traverse the unfinished order array and use orders[j].Id one by one to cancel the order based on the index j.
exchange.CancelOrder(orders[j].Id, orders[j]);
ret = true; // Once there is a cancel operation, ret is assigned a value of true. Used to trigger above Sleep, wait for re-exchange.GetOrders detection
}
}
return ret; // return ret
}
function valuesToString(values, pos) { // Value converted to a string
var result = ''; // Declare an empty string result for return
if (typeof(pos) === 'undefined') { // If the pos parameter is not passed, assign pos a value of 0.
pos = 0;
}
for (var i = pos; i < values.length; i++) { // Process values array according to the passed pos
if (i > pos) { // In addition to the first loop, add ' ' a space after the result string
result += ' ';
}
if (values[i] === null) { // If values (function argument list array) the current index's element is null then result adds 'null' string
result += 'null';
} else if (typeof(values[i]) == 'undefined') { // If it is undefined, add 'undefined'
result += 'undefined';
} else { // Remaining type do switch detection separately
switch (values[i].constructor.name) { // Check the name property of the constructor of values[i], which is the type name
case 'Date':
case 'Number':
case 'String':
case 'Function':
result += values[i].toString(); // If it is a date type, a numeric type, a string type, or a function type, call its toString function and convert it to a string, then add
break;
default:
result += JSON.stringify(values[i]); // In other cases, use the JSON.stringify function to convert to a JSON string. Add to result
break;
}
}
}
return result; // return result
}
function Trader() { // Trader function, using closures.
var vId = 0; // Order increment ID
var orderBooks = []; // Order book
var hisBooks = []; // Historical order book
var orderBooksLen = 0; // Order book length
this.Buy = function(price, amount, extra) { // Buying function, parameters: price, quantity, extended information
if (typeof(extra) === 'undefined') { // If the parameter extra is not passed in, ie typeof returns undefined
extra = ''; // Assign an empty string to extra
} else {
extra = valuesToString(arguments, 2); // The argument arguments passed when calling this.Buy function is passed to the valuesToString function.
}
vId++; //
var orderId = "V" + vId; //
orderBooks[orderId] = { // Add the attribute orderId to the order book array and initialize it with the constructed object.
Type: ORDER_TYPE_BUY, // Constructed Object Type Property: Type buy
Status: ORDER_STATE_PENDING, // State on hold
Id: 0, // orderID 0
Price: price, // price paramter price
Amount: amount, // Order quantity parameter amount
Extra: extra // Extended information A string processed by valuesToString
};
orderBooksLen++; // The length of the order book is increased by 1
return orderId; // Returns the orderId of the order constructed this time (non-exchange order ID, don't confuse.)
};
this.Sell = function(price, amount, extra) { // Basically similar to this.Buy, construct a sell order.
if (typeof(extra) === 'undefined') {
extra = '';
} else {
extra = valuesToString(arguments, 2);
}
vId++;
var orderId = "V" + vId;
orderBooks[orderId] = {
Type: ORDER_TYPE_SELL,
Status: ORDER_STATE_PENDING,
Id: 0,
Price: price,
Amount: amount,
Extra: extra
};
orderBooksLen++;
return orderId;
};
this.GetOrders = function() { // Get unfinished order information
var orders = _C(exchange.GetOrders); // Call API GetOrders to get unfinished order information Assigned to orders
for (orderId in orderBooks) { // Traversing the orderBooks in the Trader object
var order = orderBooks[orderId]; // Take out the order based on orderId
if (order.Status !== ORDER_STATE_PENDING) { // If the state of order is not equal to the suspended state, skip this loop
continue;
}
var found = false; // Initialize the found variable (marked if found) to true
for (var i = 0; i < orders.length; i++) { // Traversing data for unexecuted orders returned by the API
if (orders[i].Id == order.Id) { // When you find an order with the same order id in orderBooks, assign a value of true to find, which means find.
found = true;
break; // Jump out of the current loop
}
}
if (!found) { // If not found, push orderBooks[orderId] to orders.
orders.push(orderBooks[orderId]); // Why do you want to push like this?
}
}
return orders; // return orders
}
this.GetOrder = function(orderId) { // Get order
if (typeof(orderId) === 'number') { // If the passed argument orderId is a numeric type
return exchange.GetOrder(orderId); // Call the API GetOrder to get the order information based on the orderId and return.
}
if (typeof(hisBooks[orderId]) !== 'undefined') { // Typeof(hisBooks[orderId]) if not equal to undefined
return hisBooks[orderId]; // Return data in hisBooks with attribute as orderId
}
if (typeof(orderBooks[orderId]) !== 'undefined') { // As above, if there is a value of orderId in the orderBooks, this data is returned.
return orderBooks[orderId];
}
return null; // Return null if the above conditions are not met
};
this.Len = function() { // Returns the Trader's orderBookLen variable, which returns the order book length.
return orderBooksLen;
};
this.RealLen = function() { // Back In the order book Activate the order quantity.
var n = 0; // Initial count is 0
for (orderId in orderBooks) { // Traversing the order book
if (orderBooks[orderId].Id > 0) { // If the Id of the current order in the traversal is greater than 0, that is, 0 other than the initial time,
// indicating that the order has been placed, the order has been activated.
n++; // Cumulatively activated order
}
}
return n; // Returns the value of n, which returns the true order book length. (number of orders activated)
};
this.Poll = function(ticker, priceDiff) { //
var orders = _C(exchange.GetOrders); // Get all unexecuted orders
for (orderId in orderBooks) { // Traversing the order book
var order = orderBooks[orderId]; // Take the current order assign to order
if (order.Id > 0) { // If the order is active, ie order.Id is not 0 (already placed)
var found = false; // Variable found (mark found) is false
for (var i = 0; i < orders.length; i++) { // Find the same order number in the executed order information returned by the exchange
if (order.Id == orders[i].Id) { // If found, assign a value of true to find, which means it has been found.
found = true;
}
}
if (!found) { // If the current orderId represents an order that is not found in the order of the uncompleted order returned by the exchange.
order.Status = ORDER_STATE_CLOSED; // Updates the order corresponding to orderId in orderBooks (ie the current order variable) and updates
// the Status property to ORDER_STATE_CLOSED (ie closed)
hisBooks[orderId] = order; // The completed order is recorded in the historical order book, ie hisBooks, unified, and the unique order number orderId
delete(orderBooks[orderId]); // Delete the attribute of the order book named orderId value. (The completed order is deleted from it)
orderBooksLen--; // Order book length reduction
continue; // The following code skips the loop.
}
}
var diff = _N(order.Type == ORDER_TYPE_BUY ? (ticker.Buy - order.Price) : (order.Price - ticker.Sell));
// Diff is the difference between the planned opening price of the order in the current order book and the current real-time opening price.
var pfn = order.Type == ORDER_TYPE_BUY ? exchange.Buy : exchange.Sell; // Assign the corresponding API function reference to pfn according to the type of the order.
// That is, if the order type is a buy order, pfn is a reference to the exchange.Buy function, the same as the sell order.
if (order.Id == 0 && diff <= priceDiff) { // If the order order in the order book is not activated (ie Id is equal to 0) and the current price is less than or
// equal to the order plan price, the priceDiff passed in the parameter.
var realId = pfn(order.Price, order.Amount, order.Extra + "(distance: " + diff + (order.Type == ORDER_TYPE_BUY ? (" ask price: " + ticker.Buy) : (" bid price: " + ticker.Sell))+")");
// Execute order function, parameter passing price, quantity, order extension information + pending order distance + market data (ask price or bid price), return exchange order id
if (typeof(realId) === 'number') { // If the returned realId is a numeric type
order.Id = realId; // Assign the Id attribute of the current order order to the order book.
}
} else if (order.Id > 0 && diff > (priceDiff + 1)) { // If the order is active and the current distance is greater than the distance passed in by the parameter
var ok = true; // Declare a variable for tagging Initially set true
do { // Execute "do" first and then judge while
ok = true; // Ok assign true
exchange.CancelOrder(order.Id, "unnecessary" + (order.Type == ORDER_TYPE_BUY ? "buying" : "selling"), "placed order price:", order.Price, "volume:", order.Amount, ", distance:",
diff, order.Type == ORDER_TYPE_BUY ? ("ask price: " + ticker.Buy) : ("bid price: " + ticker.Sell));
// Cancel the pending order that is out of range. After canceling the order, print the current order information and the current distance diff.
Sleep(200); // Wait 200 milliseconds
orders = _C(exchange.GetOrders); // Call the API to get an uncompleted order in the exchange.
for (var i = 0; i < orders.length; i++) { // Traverse these unfinished orders.
if (orders[i].Id == order.Id) { // If the cancelled order is found in the list of orders that have not been completed by the exchange
ok = false; // Assign ok this variable to false, that is, no cancellation is successful.
}
}
} while (!ok); // If ok is false, then !ok is true and while will continue to repeat the loop, continue to cancel the order,
// and check if the cancellation is successful.
order.Id = 0; // Assigning a value of 0 to order.Id means that the current order is inactive.
}
}
};
}
function balanceAccount(orgAccount, initAccount) { // Balance Account Function Parameter Initial account information when the strategy is started
cancelPending(); // Call the custom function cancelPending() to cancel all pending orders.
var nowAccount = _C(exchange.GetAccount); // Declare a variable nowAccount to record the latest information about the account at the moment.
var slidePrice = 0.2; // Set the slip price when placing the order as 0.2
var ok = true; // Tag variable initially set true
while (true) { // while loop
var diff = _N(nowAccount.Stocks - initAccount.Stocks); // Calculate the difference between the current account and the initial account diff
if (Math.abs(diff) < exchange.GetMinStock()) { // If the absolute value of the currency difference is less than the minimum transaction volume of the exchange,
// the break jumps out of the loop and does not perform balancing operations.
break;
}
var depth = _C(exchange.GetDepth); // Get the exchange depth information Assign to the declared depth variable
var books = diff > 0 ? depth.Bids : depth.Asks; // According to the difference of the currency is greater than 0 or less than 0, extract the buy order array or
// sell order array in depth (equal to 0 will not be processed, it is break when it is judged to be less than GetMinStock)
// The difference between the coins is greater than 0 to sell the balance, so look at the buy order array,
// the difference between the coins is less than 0 is the opposite.
var n = 0; // Statement n initial is 0
var price = 0; // Statement price initial 0
for (var i = 0; i < books.length; i++) { // Traversing the buy or sell order array
n += books[i].Amount; // Accumulate Amount (order quantity) for each order based on the index i traversed
if (n >= Math.abs(diff)) { // If the cumulative order quantity n is greater than or equal to the currency difference, then:
price = books[i].Price; // Get the price of the current indexed order, assign it to price
break; // Jump out of the current for traversal cycle
}
}
var pfn = diff > 0 ? exchange.Sell : exchange.Buy; // Pass the sell order API (exchange.Sell) or the next buy order API (exchange.Buy) reference to the declared pfn
// based on the currency difference greater than 0 or less than 0
var amount = Math.abs(diff); // The amount of the order to be balanced is diff, the difference in the currency, assigned to the declared amount variable.
var price = diff > 0 ? (price - slidePrice) : (price + slidePrice); // The direction of buying and selling according to the difference in the currency, increase or decrease the
// slip price based on the price (slip price is to make it easier to trade), and then assign it to price
Log("start the balance", (diff > 0 ? "sell" : "buy"), amount, "of coins"); // The number of coins that the output log balances.
if (diff > 0) { // According to the direction of the buying and selling, determine whether the account currency or the amount of coins is sufficient.
amount = Math.min(nowAccount.Stocks, amount); // Make sure that the order amount will not exceed the available coins of the current account.
} else {
amount = Math.min(nowAccount.Balance / price, amount); // Make sure that the amount of order placed does not exceed the amount of money available in the current account.
}
if (amount < exchange.GetMinStock()) { // Check if the final order quantity is less than the minimum order quantity allowed by the exchange
Log("Insufficient funds, unable to balance to the initial state"); // If the order quantity is too small, the information is printed.
ok = false; // Tag balance failed
break; // Jump out of the while loop
}
pfn(price, amount); // Execute order API (pfn reference)
Sleep(1000); // Pause for 1 second
cancelPending(); // Cancel all pending orders.
nowAccount = _C(exchange.GetAccount); // Get current account information
}
if (ok) { // Execute the code inside curly braces when ok is true (balance is successful)
LogProfit(_N(nowAccount.Balance - orgAccount.Balance)); // Use the Balance property of the incoming parameter orgAccount (account information before balancing)
// to subtract the Balance property of the current account information, that is, the difference in the amount of money.
// That is, profit and loss (because the number of coins does not change, there is a slight error because some small
// amounts cannot be balanced)
Log("平衡完成", nowAccount); // The output log is balanced.
}
}
var STATE_WAIT_OPEN = 0; // Used for the state of each node in the fishTable
var STATE_WAIT_COVER = 1; // ...
var STATE_WAIT_CLOSE = 2; // ...
var ProfitCount = 0; // Profit and loss record
var BuyFirst = true; // Initial interface parameters
var IsSupportGetOrder = true; // determine the exchange support the GetOrder API function, a global variable, used to determine the start of the main function
var LastBusy = 0; // Record the last processed time object
function setBusy() { // Set Busy time
LastBusy = new Date(); // Assign LastBusy to the current time object
}
function isTimeout() { // Determine if it times out
if (MaxIdle <= 0) { // Maximum idle time (based on whether the grid is automatically moved),
// if the maximum idle time MaxIdle is set less than or equal to 0
return false; // Returns false, does not judge the timeout. That is, always return false without timeout.
}
var now = new Date(); // Get current time object
if (((now.getTime() - LastBusy.getTime()) / 1000) >= MaxIdle) { // Use the getTime function of the current time object to get the timestamp and the timestamp of LastBusy to calculate the difference,
// Divide by 1000 to calculate the number of seconds between the two time objects.
// Determine if it is greater than the maximum idle time MaxIdle
LastBusy = now; // If it is greater than, update LastBusy to the current time object now
return true; // Returns true, which is a timeout.
}
return false; // Return false no timeout
}
function onexit() { // The closing function when the program exits.
if (CancelAllWS) { // To cancel all pending orders when stop, call cancelPending() to cancel all pending orders.
Log("Exiting, try to cancel all pending orders");
cancelPending();
}
Log("Strategy successfully stopped");
Log(_C(exchange.GetAccount)); // Print the account position information when you exit the program.
}
function fishing(orgAccount, fishCount) { // Casting parameters: account information, number of casting
setBusy(); // Set LastBuys to the current timestamp
var account = _C(exchange.GetAccount); // Declare an account variable to get the current account information and assign it.
Log(account); // Output the account information at the start of the call to the fishing function.
var InitAccount = account; // Declare a variable InitAccount and assign it with account. Here is the initial account funds recorded before
// this casting, used to calculate floating profit and loss.
var ticker = _C(exchange.GetTicker); // Get the quote value assigned to the declared ticker variable
var amount = _N(AmountOnce); // According to the number of interface parameters, use _N to process the decimal places (_N defaults to 2 bits) and assign them to amount.
var amountB = [amount]; // Declare a variable called amountB is an array, initialize an element with amount
var amountS = [amount]; // Declare a variable called amountS ...
if (typeof(AmountType) !== 'undefined' && AmountType == 1) { // According to the custom amount, the order size type, if this interface parameter is not undefined,
// And AmountType is set to a custom amount on the interface, that is, the AmountType value is 1 (the index of the drop-down box)
for (var idx = 0; idx < AllNum; idx++) { // The total number of AllNum. If you set a custom amount, cycle amountB/amountS to the order quantity array according to the total number of cycles.
amountB[idx] = BAmountOnce; // Assign value to the buy order array using interface parameters
amountS[idx] = SAmountOnce; // ... to the sell order...
}
} else { // else
for (var idx = 1; idx < AllNum; idx++) { // Cycles based on the total number of grids.
switch (AmountCoefficient[0]) { // According to the interface parameter difference, the first character of the string, AmountCoefficient[0] is '+', '-', '*', '/'
case '+': // According to the interface parameters, a grid with a single addition and increment is constructed.
amountB[idx] = amountB[idx - 1] + parseFloat(AmountCoefficient.substring(1));
break;
case '-': // ...
amountB[idx] = amountB[idx - 1] - parseFloat(AmountCoefficient.substring(1));
break;
case '*':
amountB[idx] = amountB[idx - 1] * parseFloat(AmountCoefficient.substring(1));
break;
case '/':
amountB[idx] = amountB[idx - 1] / parseFloat(AmountCoefficient.substring(1));
break;
}
amountB[idx] = _N(amountB[idx], AmountDot); // buying order, buying amount, and process the data decimal places.
amountS[idx] = amountB[idx]; // Assignment
}
}
if (FirstPriceAuto) { // If the first parameter is automatically set to true if the interface parameter is set, the code inside the if curly brackets is executed.
FirstPrice = BuyFirst ? _N(ticker.Buy - PriceGrid, Precision) : _N(ticker.Sell + PriceGrid, Precision);
// The interface parameter FirstPrice sets the first price according to the BuyFirst global variable (the initial statement is true,
// and has been assigned according to the OpType at the beginning of the main).
// The price is set by the price ticker and the price parameter PriceGrid price interval.
}
// Initialize fish table
var fishTable = {}; // Declare a grid object
var uuidTable = {}; // Identification code table object
var needStocks = 0; // Required coins variable
var needMoney = 0; // Required money variable
var actualNeedMoney = 0; // Actually needed money
var actualNeedStocks = 0; // Actually needed coins
var notEnough = false; // Underfunded tag variable, initially set to false
var canNum = 0; // Available grid
for (var idx = 0; idx < AllNum; idx++) { // The structure is traversed according to the number of grid AllNum.
var price = _N((BuyFirst ? FirstPrice - (idx * PriceGrid) : FirstPrice + (idx * PriceGrid)), Precision);
// When traversing the construct, the current index idx price setting is set according to BuyFirst. The spacing between each index price is PriceGrid.
needStocks += amountS[idx]; // The number of coins sold is gradually accumulated with the cycle. (accumulated by the sell order quantity array to needStocks one by one)
needMoney += price * amountB[idx]; // The amount of money required to buy is gradually accumulated with the cycle. (....buy the order quantity array one by one...)
if (BuyFirst) { // Handling buy first
if (_N(needMoney) <= _N(account.Balance)) { // If the grid requires less money than the amount of money available on the account
actualNeedMondy = needMoney; // Assigned to the actual amount of money required
actualNeedStocks = needStocks; // Assigning to the actual number of coins required. Is there something wrong with this?
canNum++; // Cumulative number of available grids
} else { // _N(needMoney) <= _N(account.Balance) If this condition is not met, set the underfunded tag variable to true
notEnough = true;
}
} else { // Handling sell first
if (_N(needStocks) <= _N(account.Stocks)) { // Check if the required number of coins is less than the number of coins available in the account
actualNeedMondy = needMoney; // Assignment
actualNeedStocks = needStocks;
canNum++; // Cumulative number of available grids
} else {
notEnough = true; // Set true if the funding conditions are not met
}
}
fishTable[idx] = STATE_WAIT_OPEN; // According to the current index idx, set the state of the idx member (grid node) of the grid object,
// initially STATE_WAIT_OPEN (waiting to open the position)
uuidTable[idx] = -1; // The numbered object also initializes its own idx value (the node corresponding to the fishTable) to -1 based on the current idx.
}
if (!EnableAccountCheck && (canNum < AllNum)) { // If the funds check is not enabled, and the number of grids (the total number of nodes) where the node is smaller
// than the interface parameter setting can be opened.
Log("Warning, current funds can only be made", canNum, "of Grids, total grid needs", (BuyFirst ? needMoney : needStocks), "Please keep sufficient funds"); // Log outputs a warning message.
canNum = AllNum; // Update the number of openable settings for the interface parameters
}
if (BuyFirst) { // buy first
if (EnableProtectDiff && (FirstPrice - ticker.Sell) > ProtectDiff) { // Open spread protection and enter the market price minus the current bid price more than
// the market entry price protection
throw "The first buying price is higher than the market selling price" + _N(FirstPrice - ticker.Sell, Precision) + ' dollar'; // Throw an error message.
} else if (EnableAccountCheck && account.Balance < _N(needMoney)) { // If the funds check is enabled and the amount of money available for the account is less than
// the amount of money required for the grid.
if (fishCount == 1) { // If it is the first time to cast the grid
throw "Insufficient funds, need" + _N(needMoney) + "dollar"; // Throw an error, insufficient funds
} else {
Log("Insufficient funds, need", _N(needMoney), "dollar, the program only make", canNum, "of grids #ff0000"); // If it is not the first time to cast a grid, output a message.
}
} else { // In other cases, there is no capital inspection, price protection, etc.
Log('Estimated use of funds: ', _N(needMoney), "dollar"); // The output is expected to use funds.
}
} else { // sell first, The following is similar to "buy first"
if (EnableProtectDiff && (ticker.Buy - FirstPrice) > ProtectDiff) {
throw "The first selling price is higher than the market buying price" + _N(ticker.Buy - FirstPrice, Precision) + ' dollar';
} else if (EnableAccountCheck && account.Stocks < _N(needStocks)) {
if (fishCount == 1) {
throw "Insufficient funds, need" + _N(needStocks) + " of coins";
} else {
Log("Insufficient funds, need", _N(needStocks), "of coins, program only make", canNum, "of grids #ff0000");
}
} else {
Log('Estimated use of funds: ', _N(needStocks), "coins, approximately", _N(needMoney), "dollar");
}
}
var trader = new Trader(); // Constructs a Trader object, assigning it to the trader variable declared here.
var OpenFunc = BuyFirst ? exchange.Buy : exchange.Sell; // According to whether to buy and sell first, set the open function OpenFunc to refer to exchange.Buy or exchange.Sell
var CoverFunc = BuyFirst ? exchange.Sell : exchange.Buy; // same as above
if (EnableDynamic) { // Set OpenFunc/CoverFunc again according to whether the interface parameter EnableDynamic is enabled.
OpenFunc = BuyFirst ? trader.Buy : trader.Sell; // The member function Buy that references the trader object is used for dynamic pending orders (mainly because
// some exchanges limit the number of pending orders, so virtual dynamic pending orders are required)
CoverFunc = BuyFirst ? trader.Sell : trader.Buy; // same as above
}
var ts = new Date(); // Create a time object at this time (assigned to ts) to record the time at the moment.
var preMsg = ""; // Declare a variable to record the last message, the initial set to empty string
var profitMax = 0; // Maximum return
while (true) { // The main logic after the grid is casted
var now = new Date(); // Record the time when the current cycle started
var table = null; // Declare a variable
if (now.getTime() - ts.getTime() > 5000) { // Calculate whether the difference between the current time now and the recorded time ts is greater than 5000 milliseconds
if (typeof(GetCommand) == 'function' && GetCommand() == "Receiving grid") { // Check if the strategy interaction control command "receives the grid" is received,
// stops and balances to the initial state.
Log("Start executing commands to perform grid operations"); // Output information
balanceAccount(orgAccount, InitAccount); // Perform a balancing function to balance the number of coins to the initial state
return false; // This time the grid function is fishing and return false
}
ts = now; // Update ts with current time now for next comparison time
var nowAccount = _C(exchange.GetAccount); // Declare the nowAccount variable and initially been set as the current account information.
var ticker = _C(exchange.GetTicker); // Declare the ticker variable and initially been set as the current market information.
if (EnableDynamic) { // If you enable dynamic pending orders
trader.Poll(ticker, DynamicMax); // Call the Poll function of the trader object to detect and process all orders based on the
// current ticker market and the interface parameter DynamicMax.
}
var amount_diff = (nowAccount.Stocks + nowAccount.FrozenStocks) - (InitAccount.Stocks + InitAccount.FrozenStocks); // Calculate the current coin difference
var money_diff = (nowAccount.Balance + nowAccount.FrozenBalance) - (InitAccount.Balance + InitAccount.FrozenBalance); // Calculate the current money difference
var floatProfit = _N(money_diff + (amount_diff * ticker.Last)); // Calculate the current floating profit and loss of this time of casting grid
var floatProfitAll = _N((nowAccount.Balance + nowAccount.FrozenBalance - orgAccount.Balance - orgAccount.FrozenBalance) + ((nowAccount.Stocks + nowAccount.FrozenStocks
- orgAccount.Stocks - orgAccount.FrozenStocks) * ticker.Last));
// Calculate the overall floating profit and loss
var isHold = Math.abs(amount_diff) >= exchange.GetMinStock(); // If the absolute value of the coin difference at this moment is greater than the minimum trading
// volume of the exchange, it means that the position has been held.
if (isHold) { // If you have already held a position, execute the setBusy() function, which will update the LastBusy time.
setBusy(); // That is, after opening the position, the opening of the opening mechanism is started.
}
profitMax = Math.max(floatProfit, profitMax); // Refresh the maximum floating profit and loss
if (EnableAccountCheck && EnableStopLoss) { // If you initiate account detection and start a stop loss
if ((profitMax - floatProfit) >= StopLoss) { // If the maximum floating profit or loss minus the current floating profit or loss is greater than or equal to
// the maximum floating loss value, execute the code inside the curly braces
Log("Current floating profit a