Last active
February 25, 2021 19:33
-
-
Save davidlondono/800c48398e55db79a9b907fd86c1bc3f to your computer and use it in GitHub Desktop.
Analysis of strategies of https://bitcoinvsaltcoins.com
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import fetch from 'node-fetch'; | |
import readline from "readline"; | |
const rl = readline.createInterface({ | |
input: process.stdin, | |
output: process.stdout | |
}); | |
const margin_pairs = new Set([ | |
"ADABTC", | |
"ATOMBTC", | |
"BATBTC", | |
"BCHBTC", | |
"BNBBTC", | |
"DASHBTC", | |
"EOSBTC", | |
"ETCBTC", | |
"ETHBTC", | |
"IOSTBTC", | |
"IOTABTC", | |
"LINKBTC", | |
"LTCBTC", | |
"MATICBTC", | |
"NEOBTC", | |
"ONTBTC", | |
"QTUMBTC", | |
"RVNBTC", | |
"TRXBTC", | |
"VETBTC", | |
"XLMBTC", | |
"XMRBTC", | |
"XRPBTC", | |
"XTZBTC", | |
"ZECBTC", | |
]); | |
interface TradesBN { | |
id: string; | |
stratid: string; | |
stratname: string; | |
pair: string; | |
type: "LONG" | "SHORT"; | |
buy_time: string; | |
updated_time: string; | |
buy_price: string; | |
sell_price: string; | |
pnl: string; | |
yo: boolean; | |
} | |
// https://stackoverflow.com/questions/56252742/find-all-permutations-of-2-arrays-in-js | |
const transpose = <T>(array: T[][]) => array.reduce<T[][]>((r, a) => a.map<T[]>((v, i) => [...(r[i] || []), v]), []); | |
const combinations = <T>(array: T[][]) => array.reduce((a, b) => a.reduce((r, v) => r.concat(b.map(w => [].concat(v, w))), [])); | |
interface RunOptions { | |
types: TradesBN['type'][] | |
} | |
const run = async (strategy: string | number, ops: RunOptions = { types: ['LONG', 'SHORT']}) => { | |
const data: TradesBN[] = await fetch(`https://bitcoinvsaltcoins.com/api/strategy?id=${strategy}`) | |
.then(response => response.json() ); | |
const orderData = data.filter(d => ops.types.includes(d.type)); | |
const enterOperation = orderData.map((e) => ({ | |
time: Number(e.buy_time), | |
operation: 'enter', | |
...e, | |
})); | |
const exitOperation = orderData.map((e) => ({ | |
time: Number(e.updated_time), | |
operation: 'exit', | |
...e, | |
})); | |
const history = [...enterOperation,...exitOperation] | |
.sort((a,b) => a.time - b.time) | |
.filter(e => !e.yo); | |
const times = history.map(h => h.time); | |
const timeDif = Math.max(...times) - Math.min(...times) | |
const interes = 0.00125 / 100; | |
const hours = timeDif / (1000 * 60 * 60) | |
const executeTrades = ({ trades, tradeDivide, balance }: { | |
trades: typeof history, tradeDivide: number, balance: number | |
}) => { | |
let theNewBalance = balance | |
const tradesOpen = new Set(); | |
let operationLost = 0; | |
const tradeAmount = balance * tradeDivide; | |
trades.forEach(d => { | |
if (d.operation === 'enter' && theNewBalance > tradeAmount) { | |
tradesOpen.add(d.id) | |
theNewBalance -= tradeAmount; | |
} else if (d.operation === 'exit' && tradesOpen.has(d.id)) { | |
if(d.type === 'SHORT') { | |
const amount = tradeAmount / Number(d.sell_price); | |
const traded = amount * Number(d.buy_price); | |
theNewBalance += traded | |
} else { | |
const amount = tradeAmount / Number(d.buy_price); | |
const traded = amount * Number(d.sell_price); | |
theNewBalance += traded | |
} | |
} else if (d.operation === 'enter') { | |
operationLost += 1; | |
// console.log("LOST TRADE", d, balance) | |
} | |
}); | |
return { | |
balance: theNewBalance, | |
operationLost | |
} | |
} | |
const execute = (tradeDivide: number, divide: number) => { | |
const balance = 1 * divide; | |
const balancePreMargin = (1 - balance); | |
const balanceMargin = balancePreMargin * 3.9; | |
const borrowed = balanceMargin - balancePreMargin; | |
// console.log({balance,balancePreMargin,balanceMargin,borrowed}) | |
const tradesMargin = history.filter((trade) => margin_pairs.has(trade.pair)); | |
const tradesSpot = history.filter((trade) => !margin_pairs.has(trade.pair)); | |
const executedMargin = executeTrades({ | |
trades:tradesMargin, | |
tradeDivide, | |
balance: balanceMargin | |
}); | |
const executedSpot = executeTrades({ | |
trades: tradesSpot, | |
tradeDivide, | |
balance | |
}); | |
const lostTades = executedMargin.operationLost + executedSpot.operationLost | |
// console.log({ executedMargin, executedSpot }) | |
const totalInteres = interes * hours * borrowed; | |
const finalBalance = executedMargin.balance + executedSpot.balance - (borrowed + totalInteres) | |
// console.log("finalBalance", finalBalance) | |
return { | |
lostTades, | |
finalBalance, | |
totalInteres | |
}; | |
} | |
//execute(0.5, 0.5) | |
//execute(0, 0) | |
type TheBestCase = {from: number, to: number, steps: number} | |
const findTheBest = (table: [TheBestCase,TheBestCase], fn: (one: number, two: number) => number) => { | |
const counts = 10; | |
// console.log("steps",step) | |
// console.log("to",to); | |
const [stepsOne, stepsTwo] = table.map(({ from, to , steps }) => (to - from) / counts) | |
const [listOne, listTwo] = table.map(({ from, to, steps }) => { | |
const step = (to - from) / steps; | |
return [...Array(steps)].map((_,x) => from + x * step) | |
}); | |
let max = 0; | |
let best: number[] = []; | |
listOne.forEach(val => { | |
listTwo.forEach(val2 => { | |
const value = fn(val, val2); | |
if (max < value) { | |
max = value; | |
best = [val, val2]; | |
// console.log(val, val2, max) | |
process.stdout.write(`\r best match tradeAmount: ${val.toFixed(10)} divide: ${val2.toFixed(10)}`); | |
} | |
}) | |
}) | |
process.stdout.write(`\r\n`); | |
return { | |
max, | |
best | |
}; | |
} | |
const theBestMatch = findTheBest([{ from: 0, to: 1, steps: 1000},{ from: 0, to: 1, steps: 100}], (a,b) => execute(a,b).finalBalance); | |
const { lostTades, totalInteres } = execute(theBestMatch.best[0], theBestMatch.best[1]); | |
const days = timeDif / (1000*60*60*24); | |
console.log(`Earning %${(100 * (theBestMatch.max - 1) / days).toFixed(2)} a day`, ) | |
console.log("lostTrades", lostTades) | |
console.log("totalInteres", totalInteres) | |
console.log(theBestMatch) | |
} | |
const requestCode = () => { | |
rl.question("what code", function(code) { | |
run(code); | |
requestCode() | |
}); | |
} | |
requestCode() | |
rl.on("close", function() { | |
console.log("\nBYE BYE !!!"); | |
process.exit(0); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment