two platforms hedging JS
JavaScript strategy by 7meter.
JavaScriptOther
The original spec has no written description. Read the source below.
Parameters
| Name | Default | What it controls |
|---|---|---|
| MinSpreadA | 0.51 | A->BSpread |
| MinSpreadB | 0.52 | B->ASpread |
| MaxAmount | 0.3 | Maximum operation volume |
| BalanceTime | 10 | Balance period (seconds) |
| LoopInterval | 200 | Polling Interval(ms) |
| Button | Default | Description |
| ---- | ---- | ---- |
| A->B | 0.51 | Change Spread(A->B) |
| B->A | 0.52 | Change Spread(B->A) |
Source JavaScript
function cancelAll(){
var ref = false;
for(var e in exchanges){
while(true){
var n = 0;
var my_orders = _C(exchanges[e].GetOrders);
for(var order1 in my_orders){
ref = true;
e.CancelOrder(my_orders[order1].Id);
n += 1;
}
if(n==0){
break;
}
}
}
return ref;
}
function main(){
if(exchanges.length != 2){
throw("Only two exchanges are supported");
}
LogReset();
LogProfitReset();
cancelAll();
var initStocks = 0.0;
var initBalance = 0.0;
var minAmount = 0.1;
var lastTradeTime = 0;
var lastTradeErrExchange = '';
var accountsCache = [];
var hedgeNum = [0, 0];
var names = [];
var baseCurrency = exchange.GetCurrency();
for(var e in exchanges){
if(exchanges[e].GetCurrency() != baseCurrency){
throw("It has to be the same currency to hedge:"+baseCurrency);
}
names.push(exchanges[e].GetName());
var account = _C(exchanges[e].GetAccount);
accountsCache.push(account);
initStocks += account.Stocks;
initBalance += account.Balance;
}
if(baseCurrency == "BTC"){
minAmount = 0.01
} else {
minAmount = 0.1
}
Log("all balance:", _N(initBalance), "all stocks", _N(initStocks))
while(true){
if(accountsCache.length <= 0){
for(var e in exchanges){
var account1 = _C(exchanges[e].GetAccount);
accountsCache.push(account1);
}
}
Sleep(LoopInterval);
cmd = GetCommand();
if(cmd){
Log("CMD", cmd);
var arr = cmd.split(":");
if(arr[0]=="A->B"){
MinSpreadA = parseFloat(arr[1]);
} else if(arr[0]=="B->A"){
MinSpreadB = parseFloat(arr[1]);
}
}
var depthA = exchanges[0].GetDepth();
if (!depthA){
continue;
}
var depthB = exchanges[1].GetDepth();
if (!depthB){
continue;
}
var time = new Date();
if(lastTradeTime > 0 && time.getTime() - lastTradeTime > BalanceTime){
var needUpdate = cancelAll();
if (!needUpdate){
for(var account2 in accountsCache){
if(accountsCache[account2].FrozenBalance >= 0.1 || accountsCache[account2].FrozenStocks >= 0.001){
needUpdate = true;
break;
}
}
}
if (needUpdate){
for(var k in exchanges){
account3 = _C(exchanges[k].GetAccount);
accountsCache.push(account3);
}
}
var nowStocks = 0.0;
var nowBalance = 0.0;
for(var account4 in accountsCache){
nowBalance += accountsCache[account4].Balance;
nowStocks += accountsCache[account4].Stocks;
}
var diff = _N(nowStocks-initStocks, 5);
var isReverse;
if(Math.abs(diff) < minAmount){
LogProfit(_N(nowBalance-initBalance, 3), "all balance", _N(nowBalance), "all stocks", _N(nowStocks), "stock offset:", diff);
lastTradeTime = 0;
} else if(diff > minAmount){
isReverse = depthA.Bids[0].Price < depthB.Bids[0].Price;
} else if(-diff > minAmount){
isReverse = depthA.Asks[0].Price > depthB.Asks[0].Price;
}
if(isReverse != null){
var depths = [depthA, depthB];
var opAmount;
var kk;
if(isReverse){
kk = [1, 0];
} else{
kk = [0, 1];
}
for(var pos in kk){
if(diff > minAmount){
opAmount = Math.min(diff, accountsCache[pos].Stocks, depths[pos].Bids[0].Amount + depths[pos].Bids[1].Amount);
diff = -opAmount;
if(opAmount >= minAmount){
exchanges[pos].Sell(depths[pos].Bids[1].Price, opAmount);
}
} else if(-diff >= minAmount){
opAmount = Math.min(-diff, _N(accountsCache[pos].Balance / depths[pos].Asks[1].Price, 3), depths[pos].Asks[0].Amount + depths[pos].Asks[1].Amount);
diff += opAmount;
if (opAmount >= minAmount){
exchanges[pos].Buy(depths[pos].Asks[1].Price, opAmount);
}
}
}
if (opAmount != undefined){
var time1 = new Date();
lastTradeTime = time1.getTime();
accountsCache = [];
}
}
continue;
}
var diffA = _N(depthA.Bids[0].Price - depthB.Asks[0].Price, 3)
var diffB = _N(depthB.Bids[0].Price - depthA.Asks[0].Price, 3)
LogStatus(JSON.stringify({type: 'table', title: 'status', cols: ['name', 'money', 'frozenmoney', 'stock', 'frozenstock', 'buyone', 'sellone', 'threshold', 'offset', 'num of times'], rows: [[names[0], accountsCache[0].Balance, accountsCache[0].FrozenBalance, accountsCache[0].Stocks, accountsCache[0].FrozenStocks, depthA.Bids[0].Price, depthA.Asks[0].Price, MinSpreadA, diffA, hedgeNum[0]], [names[1], accountsCache[1].Balance, accountsCache[1].FrozenBalance, accountsCache[1].Stocks, accountsCache[1].FrozenStocks, depthB.Bids[0].Price, depthB.Asks[0].Price, MinSpreadB, diffB, hedgeNum[0]]]}));
HPos = 0;
if (diffA >= MinSpreadA){
orderH = depthA.Bids[0];
orderL = depthB.Asks[0];
exchangeH = 0;
exchangeL = 1;
accountH = accountsCache[0];
accountL = accountsCache[1];
}
else if (diffB >= MinSpreadB){
HPos = 1;
orderH = depthB.Bids[0];
orderL = depthA.Asks[0];
exchangeH = 1;
exchangeL = 0;
accountH = accountsCache[1];
accountL = accountsCache[0];
}
else{
continue;
}
var opPrice = _N((orderH.Price + orderL.Price) / 2.0, 2);
var opAmount = Math.min(MaxAmount, orderH.Amount, orderL.Amount, accountH.Stocks, _N(accountL.Balance / opPrice, 3));
if(opAmount >= minAmount){
var tasks = [[exchangeH, "H"], [exchangeL, "L"]];
if(lastTradeErrExchange == "L"){
tasks.reverse();
}
lastTradeErrExchange = "";
for(var task in tasks){
if(tasks[task][1] == "H"){
var id = exchanges[tasks[task][0]].Sell(opPrice, opAmount);
if(id == undefined){
lastTradeErrExchange = tasks[task][1];
break;
}
}
if(tasks[task][1] == "L"){
var id = exchanges[tasks[task][0]].Buy(opPrice, opAmount);
if(id == undefined){
lastTradeErrExchange = tasks[task][1];
break;
}
}
}
var time = new Date();
lastTradeTime = time.getTime();
accountsCache = []
hedgeNum[HPos] += 1
}
}
}Published by 7meter on the FMZ strategy square · last modified 2018-01-22. Collected in the Quant Trading Vault. Unvalidated research: re-test with your own data and costs before trusting it.
Build this with AgenKit
A spec is not a trading system. Paste this into your coding agent and AgenKit runs a specialist team — architecture, test-first build, risk gates, review — with paper trading on by default.
/agenkit build a production-grade trading bot with a backtest engine, risk controls and paper trading by default from strategies/two-platforms-hedging-JS.md- npx agenkit install engineering-kit in your project
- Paste the command into your agent and approve each phase
- Get tests, backtest, risk controls and a paper-trading switch
Understand it first
Before you run this, read the lesson behind the idea and how to backtest it honestly. Specs like this one are the survivors of an unknown number of trials; deflate their results accordingly.