price multipliers instead of ticks
This commit is contained in:
parent
2205ae719b
commit
6a012c5fd9
2 changed files with 186 additions and 129 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -23,3 +23,5 @@ docs/
|
|||
*~
|
||||
*.swp
|
||||
*.swo
|
||||
.playwright-mcp/
|
||||
|
||||
|
|
|
|||
|
|
@ -125,10 +125,19 @@
|
|||
<body>
|
||||
<h2>Kraiken Liquidity Position Simulator</h2>
|
||||
<div style="background-color: #e3f2fd; border-radius: 4px; padding: 15px; margin-bottom: 20px; border-left: 4px solid #2196f3;">
|
||||
<strong>📊 Anti-Arbitrage Three-Position Strategy</strong><br>
|
||||
<em>Floor</em>: Deep liquidity position - contains ETH when below current price, KRAIKEN when above<br>
|
||||
<em>Anchor</em>: Shallow liquidity around current price for fast slippage<br>
|
||||
<em>Discovery</em>: Edge liquidity position - contains KRAIKEN when below current price, ETH when above
|
||||
<strong>📊 Anti-Arbitrage Three-Position Strategy (Uniswap V3 1% Pool)</strong><br>
|
||||
<br>
|
||||
<strong>Position Strategy:</strong><br>
|
||||
<em>Floor</em>: Deep liquidity position - holds ETH when ETH is cheap (below current price)<br>
|
||||
<em>Anchor</em>: Shallow liquidity around current price for fast price discovery<br>
|
||||
<em>Discovery</em>: Edge liquidity position - holds KRAIKEN when ETH is expensive (above current price)<br>
|
||||
<br>
|
||||
<strong>Price Multiples:</strong> Shows ETH price relative to current (1x):<br>
|
||||
• 0.5x = ETH is half as expensive (Floor position holds ETH)<br>
|
||||
• 1x = Current ETH price (red dashed line)<br>
|
||||
• 2x = ETH is twice as expensive (Discovery position holds KRAIKEN)<br>
|
||||
<br>
|
||||
<em>Note: The x-axis automatically adjusts based on token ordering in the pool</em>
|
||||
</div>
|
||||
<div id="status">Loading profitable scenario data...</div>
|
||||
<textarea id="csvInput" placeholder="Paste CSV formatted data here..." style="display: none;"></textarea>
|
||||
|
|
@ -310,6 +319,24 @@
|
|||
return Math.sqrt(price);
|
||||
}
|
||||
|
||||
// Convert tick to price multiple relative to current price
|
||||
// This represents ETH price multiples (how expensive ETH is relative to current)
|
||||
function tickToPriceMultiple(tick, currentTick, token0isWeth) {
|
||||
const price = tickToPrice(tick);
|
||||
const currentPrice = tickToPrice(currentTick);
|
||||
|
||||
if (token0isWeth) {
|
||||
// When ETH is token0, price = KRAIKEN/ETH
|
||||
// We want ETH price multiple, so we need to invert
|
||||
// Higher tick = more KRAIKEN per ETH = cheaper ETH
|
||||
return currentPrice / price;
|
||||
} else {
|
||||
// When KRAIKEN is token0, price = ETH/KRAIKEN
|
||||
// This is already ETH price, so just divide
|
||||
return price / currentPrice;
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate the invariant liquidity value from token amounts
|
||||
// This represents the actual liquidity deployed to the position, independent of current price
|
||||
function calculateInvariantLiquidity(token0Amount, token1Amount, tickLower, tickUpper, positionName = '') {
|
||||
|
|
@ -486,24 +513,6 @@
|
|||
header.innerHTML = `<h3>${precedingAction}</h3>`;
|
||||
scenarioContainer.appendChild(header);
|
||||
|
||||
// Create legend
|
||||
const legend = document.createElement('div');
|
||||
legend.className = 'legend';
|
||||
legend.innerHTML = `
|
||||
<div class="legend-item">
|
||||
<div class="legend-color floor"></div>
|
||||
<span>Floor Position (Foundation)</span>
|
||||
</div>
|
||||
<div class="legend-item">
|
||||
<div class="legend-color anchor"></div>
|
||||
<span>Anchor Position (Current Price)</span>
|
||||
</div>
|
||||
<div class="legend-item">
|
||||
<div class="legend-color discovery"></div>
|
||||
<span>Discovery Position (Growth)</span>
|
||||
</div>
|
||||
`;
|
||||
scenarioContainer.appendChild(legend);
|
||||
|
||||
// Create charts container
|
||||
const chartsContainer = document.createElement('div');
|
||||
|
|
@ -526,29 +535,60 @@
|
|||
scenarioContainer.appendChild(chartsContainer);
|
||||
|
||||
// Create summary panel
|
||||
const summaryPanel = createSummaryPanel(positions, currentTick);
|
||||
const summaryPanel = createSummaryPanel(positions, currentTick, token0isWeth);
|
||||
scenarioContainer.appendChild(summaryPanel);
|
||||
|
||||
// Add to page
|
||||
document.getElementById('simulations').appendChild(scenarioContainer);
|
||||
|
||||
// Create the combined chart
|
||||
createCombinedChart(combinedChart, positions, currentTick, totalLiquidity);
|
||||
createCombinedChart(combinedChart, positions, currentTick, totalLiquidity, token0isWeth);
|
||||
}
|
||||
|
||||
function createCombinedChart(chartDiv, positions, currentTick, totalLiquidity) {
|
||||
function createCombinedChart(chartDiv, positions, currentTick, totalLiquidity, token0isWeth) {
|
||||
const positionKeys = ['floor', 'anchor', 'discovery'];
|
||||
|
||||
// Calculate bar widths to represent actual tick ranges
|
||||
const barWidths = positionKeys.map(key => {
|
||||
// Convert positions to price multiples
|
||||
const priceMultiplePositions = {};
|
||||
|
||||
positionKeys.forEach(key => {
|
||||
const pos = positions[key];
|
||||
return pos.tickUpper - pos.tickLower; // Width = actual tick range
|
||||
const lowerMultiple = tickToPriceMultiple(pos.tickLower, currentTick, token0isWeth);
|
||||
const upperMultiple = tickToPriceMultiple(pos.tickUpper, currentTick, token0isWeth);
|
||||
const centerMultiple = tickToPriceMultiple(pos.tickLower + (pos.tickUpper - pos.tickLower) / 2, currentTick, token0isWeth);
|
||||
|
||||
priceMultiplePositions[key] = {
|
||||
lowerMultiple: lowerMultiple,
|
||||
upperMultiple: upperMultiple,
|
||||
centerMultiple: centerMultiple,
|
||||
width: upperMultiple - lowerMultiple,
|
||||
...pos
|
||||
};
|
||||
|
||||
console.log(`Position ${key}:`, {
|
||||
ticks: [pos.tickLower, pos.tickUpper],
|
||||
currentTick: currentTick,
|
||||
multiples: [lowerMultiple, upperMultiple],
|
||||
centerMultiple: centerMultiple,
|
||||
token0isWeth: token0isWeth
|
||||
});
|
||||
|
||||
// Calculate bar positions (centered in tick ranges)
|
||||
// Warn about extreme positions
|
||||
if (pos.tickLower > 180000 || pos.tickUpper > 180000) {
|
||||
console.warn(`EXTREME TICKS: ${key} position has ticks above 180000, which represents extreme price multiples`);
|
||||
}
|
||||
});
|
||||
|
||||
// Calculate bar widths to represent actual price multiple ranges
|
||||
const barWidths = positionKeys.map(key => {
|
||||
const pos = priceMultiplePositions[key];
|
||||
return pos.width; // Width in price multiple space
|
||||
});
|
||||
|
||||
// Calculate bar positions (centered in price multiple ranges)
|
||||
const barPositions = positionKeys.map(key => {
|
||||
const pos = positions[key];
|
||||
return pos.tickLower + (pos.tickUpper - pos.tickLower) / 2;
|
||||
const pos = priceMultiplePositions[key];
|
||||
return pos.centerMultiple;
|
||||
});
|
||||
|
||||
// ETH trace (left y-axis)
|
||||
|
|
@ -572,8 +612,8 @@
|
|||
}
|
||||
},
|
||||
text: positionKeys.map(key => {
|
||||
const pos = positions[key];
|
||||
return `${pos.name}<br>ETH: ${pos.eth.toFixed(6)}<br>Range: [${pos.tickLower}, ${pos.tickUpper}]`;
|
||||
const pos = priceMultiplePositions[key];
|
||||
return `${pos.name}<br>ETH: ${pos.eth.toFixed(6)}<br>Range: ${pos.lowerMultiple.toFixed(3)}x - ${pos.upperMultiple.toFixed(3)}x`;
|
||||
}),
|
||||
hoverinfo: 'text'
|
||||
};
|
||||
|
|
@ -603,20 +643,25 @@
|
|||
}
|
||||
},
|
||||
text: positionKeys.map(key => {
|
||||
const pos = positions[key];
|
||||
return `${pos.name}<br>KRAIKEN: ${pos.kraiken.toFixed(6)}<br>Range: [${pos.tickLower}, ${pos.tickUpper}]`;
|
||||
const pos = priceMultiplePositions[key];
|
||||
return `${pos.name}<br>KRAIKEN: ${pos.kraiken.toFixed(6)}<br>Range: ${pos.lowerMultiple.toFixed(3)}x - ${pos.upperMultiple.toFixed(3)}x`;
|
||||
}),
|
||||
hoverinfo: 'text'
|
||||
};
|
||||
|
||||
// Calculate x-axis range based on position ranges with some padding
|
||||
const allTicks = positionKeys.flatMap(key => [positions[key].tickLower, positions[key].tickUpper]);
|
||||
const minTick = Math.min(...allTicks);
|
||||
const maxTick = Math.max(...allTicks);
|
||||
const tickRange = maxTick - minTick;
|
||||
const padding = tickRange * 0.1; // 10% padding on each side
|
||||
const xAxisMin = minTick - padding;
|
||||
const xAxisMax = maxTick + padding;
|
||||
// Cap extreme values to keep chart readable
|
||||
const MAX_REASONABLE_MULTIPLE = 50; // Cap at 50x for readability
|
||||
const MIN_REASONABLE_MULTIPLE = 0.02; // Cap at 0.02x for readability
|
||||
|
||||
const allMultiples = positionKeys.flatMap(key => [priceMultiplePositions[key].lowerMultiple, priceMultiplePositions[key].upperMultiple]);
|
||||
const cappedMultiples = allMultiples.map(m => Math.min(MAX_REASONABLE_MULTIPLE, Math.max(MIN_REASONABLE_MULTIPLE, m)));
|
||||
const minMultiple = Math.min(...cappedMultiples);
|
||||
const maxMultiple = Math.max(...cappedMultiples);
|
||||
const multipleRange = maxMultiple - minMultiple;
|
||||
const padding = multipleRange * 0.1; // 10% padding on each side
|
||||
const xAxisMin = Math.max(0.01, minMultiple - padding); // Don't go below 0.01x
|
||||
const xAxisMax = Math.min(100, maxMultiple + padding); // Cap at 100x max
|
||||
|
||||
// Debug logging for chart range
|
||||
console.log('Chart x-axis range:', { xAxisMin, xAxisMax });
|
||||
|
|
@ -630,14 +675,23 @@
|
|||
// Calculate max values for proper y-axis alignment
|
||||
const maxEth = Math.max(...positionKeys.map(key => positions[key].eth));
|
||||
const maxKraiken = Math.max(...positionKeys.map(key => positions[key].kraiken));
|
||||
const showPriceLine = currentTick >= xAxisMin && currentTick <= xAxisMax;
|
||||
const showPriceLine = true; // Always show price line at 1x
|
||||
|
||||
// Create liquidity × ticks traces for each position
|
||||
const liquidityTraces = positionKeys.map(key => {
|
||||
const pos = positions[key];
|
||||
// Create liquidity × ticks traces for each position using shape/filled area approach
|
||||
const liquidityTraces = [];
|
||||
const shapes = [];
|
||||
|
||||
positionKeys.forEach((key, index) => {
|
||||
const pos = priceMultiplePositions[key];
|
||||
const tickRange = pos.tickUpper - pos.tickLower;
|
||||
const totalLiquidity = pos.liquidity * tickRange;
|
||||
|
||||
// Skip positions with zero liquidity
|
||||
if (pos.liquidity === 0 || totalLiquidity === 0) {
|
||||
console.warn(`Skipping ${key} position: zero liquidity`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Debug logging for very small or large values
|
||||
if (totalLiquidity < 1 || tickRange > 10000 || pos.tickLower > 180000) {
|
||||
console.log(`Warning: ${key} position has unusual values:`, {
|
||||
|
|
@ -645,108 +699,104 @@
|
|||
tickRange: tickRange,
|
||||
totalLiquidity: totalLiquidity,
|
||||
ticks: [pos.tickLower, pos.tickUpper],
|
||||
tickCenter: pos.tickLower + (pos.tickUpper - pos.tickLower) / 2
|
||||
lowerMultiple: pos.lowerMultiple,
|
||||
upperMultiple: pos.upperMultiple
|
||||
});
|
||||
}
|
||||
|
||||
// Note: minVisibleLiquidity will be calculated after all positions are processed
|
||||
// Create a filled area for each position to show its exact range
|
||||
// Cap display coordinates to keep within visible range
|
||||
// For extremely low positions, ensure they're visible at the left edge
|
||||
let displayLower = pos.lowerMultiple;
|
||||
let displayUpper = pos.upperMultiple;
|
||||
|
||||
// Note: Width adjustment will be done after x-axis range is calculated
|
||||
const visibleWidth = tickRange;
|
||||
|
||||
return {
|
||||
x: [pos.tickLower + (pos.tickUpper - pos.tickLower) / 2],
|
||||
y: [totalLiquidity], // Will be adjusted later
|
||||
width: visibleWidth,
|
||||
type: 'bar',
|
||||
name: `${pos.name} Total Liquidity`,
|
||||
marker: {
|
||||
color: POSITION_COLORS[key],
|
||||
opacity: 0.8,
|
||||
line: {
|
||||
color: 'white',
|
||||
width: 2
|
||||
// Ensure positions are visible even at extreme values
|
||||
if (pos.upperMultiple < 0.01) {
|
||||
// Position is entirely below 0.01x - show it at the left edge
|
||||
displayLower = xAxisMin;
|
||||
displayUpper = xAxisMin * 1.5;
|
||||
} else if (pos.lowerMultiple > 50) {
|
||||
// Position is entirely above 50x - show it at the right edge
|
||||
displayLower = xAxisMax * 0.8;
|
||||
displayUpper = xAxisMax;
|
||||
} else {
|
||||
// Normal capping for positions that span the visible range
|
||||
displayLower = Math.max(xAxisMin, Math.min(xAxisMax, pos.lowerMultiple));
|
||||
displayUpper = Math.max(xAxisMin, Math.min(xAxisMax, pos.upperMultiple));
|
||||
}
|
||||
|
||||
// Add indicator if position extends beyond visible range
|
||||
let rangeText = `Range: ${pos.lowerMultiple.toFixed(3)}x - ${pos.upperMultiple.toFixed(3)}x`;
|
||||
let extendsBeyond = false;
|
||||
if (pos.lowerMultiple < xAxisMin || pos.upperMultiple > xAxisMax) {
|
||||
rangeText += ' <b>(extends beyond chart)</b>';
|
||||
extendsBeyond = true;
|
||||
}
|
||||
|
||||
// For extremely high or low multiples, show in scientific notation
|
||||
if (pos.upperMultiple > 100 || pos.lowerMultiple < 0.01) {
|
||||
const lowerStr = pos.lowerMultiple < 0.01 ? pos.lowerMultiple.toExponential(2) : pos.lowerMultiple.toFixed(3) + 'x';
|
||||
const upperStr = pos.upperMultiple > 100 ? pos.upperMultiple.toExponential(2) : pos.upperMultiple.toFixed(3) + 'x';
|
||||
rangeText = `Range: ${lowerStr} - ${upperStr}`;
|
||||
|
||||
// Check if this is likely a VWAP protection position
|
||||
if (key === 'floor' && (pos.lowerMultiple < 0.01 || pos.upperMultiple > 100)) {
|
||||
rangeText += ' <b>(VWAP Protection - ETH Scarcity)</b>';
|
||||
} else {
|
||||
rangeText += ' <b>(extreme range)</b>';
|
||||
}
|
||||
}
|
||||
|
||||
const trace = {
|
||||
x: [displayLower, displayLower, displayUpper, displayUpper],
|
||||
y: [0, totalLiquidity, totalLiquidity, 0],
|
||||
fill: 'toself',
|
||||
fillcolor: POSITION_COLORS[key],
|
||||
opacity: extendsBeyond ? 0.5 : 0.7,
|
||||
type: 'scatter',
|
||||
mode: 'lines',
|
||||
line: {
|
||||
color: POSITION_COLORS[key],
|
||||
width: 2,
|
||||
dash: extendsBeyond ? 'dash' : 'solid'
|
||||
},
|
||||
text: `${pos.name}<br>Liquidity: ${pos.liquidity.toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2})}<br>Tick Range: ${tickRange.toLocaleString()}<br>Total (L×Ticks): ${totalLiquidity.toLocaleString(undefined, {minimumFractionDigits: 0, maximumFractionDigits: 0})}<br>ETH: ${pos.eth.toFixed(6)}<br>KRAIKEN: ${pos.kraiken.toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2})}<br>Range: [${pos.tickLower.toLocaleString()}, ${pos.tickUpper.toLocaleString()}]`,
|
||||
name: pos.name,
|
||||
text: `${pos.name}<br>Liquidity: ${pos.liquidity.toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2})}<br>Tick Range: ${tickRange.toLocaleString()}<br>Total (L×Ticks): ${totalLiquidity.toLocaleString(undefined, {minimumFractionDigits: 0, maximumFractionDigits: 0})}<br>ETH: ${pos.eth.toFixed(6)}<br>KRAIKEN: ${pos.kraiken.toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2})}<br>${rangeText}`,
|
||||
hoverinfo: 'text',
|
||||
showlegend: false
|
||||
showlegend: true
|
||||
};
|
||||
|
||||
liquidityTraces.push(trace);
|
||||
});
|
||||
|
||||
const data = liquidityTraces;
|
||||
|
||||
// Calculate max and min total liquidity (L × ticks) for y-axis scaling
|
||||
const totalLiquidities = positionKeys.map(key => {
|
||||
const pos = positions[key];
|
||||
return pos.liquidity * (pos.tickUpper - pos.tickLower);
|
||||
});
|
||||
const maxTotalLiquidity = Math.max(...totalLiquidities);
|
||||
const minTotalLiquidity = Math.min(...totalLiquidities.filter(l => l > 0));
|
||||
const pos = priceMultiplePositions[key];
|
||||
const tickRange = pos.tickUpper - pos.tickLower;
|
||||
return pos.liquidity * tickRange;
|
||||
}).filter(l => l > 0); // Only consider non-zero liquidities
|
||||
|
||||
// Calculate x-axis range first
|
||||
const allTicksForRange = [];
|
||||
positionKeys.forEach(key => {
|
||||
allTicksForRange.push(positions[key].tickLower, positions[key].tickUpper);
|
||||
});
|
||||
allTicksForRange.push(currentTick);
|
||||
|
||||
const minTickForWidth = Math.min(...allTicksForRange);
|
||||
const maxTickForWidth = Math.max(...allTicksForRange);
|
||||
const tickRangeTotal = maxTickForWidth - minTickForWidth;
|
||||
const paddingForWidth = tickRangeTotal * 0.1;
|
||||
const xAxisMinForWidth = minTickForWidth - paddingForWidth;
|
||||
const xAxisMaxForWidth = maxTickForWidth + paddingForWidth;
|
||||
const xRange = xAxisMaxForWidth - xAxisMinForWidth;
|
||||
|
||||
// Calculate minimum visible width as 2% of x-axis range
|
||||
const minVisibleWidth = xRange * 0.02;
|
||||
|
||||
// Adjust bar widths to ensure visibility
|
||||
liquidityTraces.forEach((trace, index) => {
|
||||
const pos = positions[positionKeys[index]];
|
||||
const actualWidth = pos.tickUpper - pos.tickLower;
|
||||
if (actualWidth < minVisibleWidth) {
|
||||
trace.width = minVisibleWidth;
|
||||
// Add note about width adjustment
|
||||
trace.text += `<br><i>(Width expanded for visibility - actual: ${actualWidth} ticks)</i>`;
|
||||
}
|
||||
});
|
||||
|
||||
// Sort liquidity values to find appropriate thresholds
|
||||
const sortedLiquidities = [...totalLiquidities].sort((a, b) => a - b);
|
||||
|
||||
// Ensure all bars are visible on the log scale
|
||||
// Set minimum height to be 2% of the median value, which should make all bars clearly visible
|
||||
const medianLiquidity = sortedLiquidities[Math.floor(sortedLiquidities.length / 2)];
|
||||
const minVisibleLiquidity = medianLiquidity * 0.02;
|
||||
|
||||
// Adjust y values to ensure minimum visibility
|
||||
liquidityTraces.forEach((trace, index) => {
|
||||
const actualValue = totalLiquidities[index];
|
||||
if (actualValue < minVisibleLiquidity) {
|
||||
trace.y[0] = minVisibleLiquidity;
|
||||
// Add a note to the hover text that this value was adjusted for visibility
|
||||
trace.text += `<br><i>(Height adjusted for visibility - actual: ${actualValue.toExponential(2)})</i>`;
|
||||
}
|
||||
});
|
||||
const maxTotalLiquidity = totalLiquidities.length > 0 ? Math.max(...totalLiquidities) : 1;
|
||||
const minTotalLiquidity = totalLiquidities.length > 0 ? Math.min(...totalLiquidities) : 0.1;
|
||||
|
||||
// Ensure minimum is at least 1e-10 for log scale
|
||||
const yMin = Math.max(1e-10, Math.min(minTotalLiquidity / 100, minVisibleLiquidity / 10));
|
||||
const yMin = Math.max(1e-10, minTotalLiquidity / 100);
|
||||
const yMax = maxTotalLiquidity * 10;
|
||||
|
||||
if (showPriceLine) {
|
||||
const priceLineTrace = {
|
||||
x: [currentTick, currentTick],
|
||||
y: [yMin, maxTotalLiquidity * 10], // Use log scale range
|
||||
x: [1, 1], // Current price is always at 1x
|
||||
y: [yMin, yMax], // Use calculated y range
|
||||
mode: 'lines',
|
||||
line: {
|
||||
color: 'red',
|
||||
width: 3,
|
||||
dash: 'dash'
|
||||
},
|
||||
name: 'Current Price',
|
||||
hoverinfo: 'x',
|
||||
text: [`Current Price: ${currentTick}`],
|
||||
name: 'Current Price (1x)',
|
||||
hoverinfo: 'name',
|
||||
showlegend: true
|
||||
};
|
||||
data.push(priceLineTrace);
|
||||
|
|
@ -754,14 +804,17 @@
|
|||
|
||||
const layout = {
|
||||
title: {
|
||||
text: `Total Liquidity Distribution (L × Tick Range) - Current Price: ${currentTick}${showPriceLine ? '' : ' - Outside Range'}`,
|
||||
text: `Total Liquidity Distribution (L × Tick Range)`,
|
||||
font: { size: 16 }
|
||||
},
|
||||
xaxis: {
|
||||
title: 'Price Ticks',
|
||||
title: 'Price Multiple (relative to current price)',
|
||||
showgrid: true,
|
||||
gridcolor: '#e0e0e0',
|
||||
range: [xAxisMin, xAxisMax]
|
||||
range: [Math.log10(xAxisMin), Math.log10(xAxisMax)],
|
||||
tickformat: '.2f',
|
||||
ticksuffix: 'x',
|
||||
type: 'log' // Use log scale for better visualization of price multiples
|
||||
},
|
||||
yaxis: {
|
||||
title: 'Total Liquidity (L × Ticks)',
|
||||
|
|
@ -770,7 +823,7 @@
|
|||
gridcolor: '#e0e0e0',
|
||||
dtick: 1, // Major gridlines at powers of 10
|
||||
tickformat: '.0e', // Scientific notation
|
||||
range: [Math.log10(yMin), Math.log10(maxTotalLiquidity * 10)]
|
||||
range: [Math.log10(yMin), Math.log10(yMax)]
|
||||
},
|
||||
showlegend: true,
|
||||
legend: {
|
||||
|
|
@ -783,7 +836,7 @@
|
|||
plot_bgcolor: 'white',
|
||||
paper_bgcolor: 'white',
|
||||
margin: { l: 60, r: 60, t: 60, b: 50 },
|
||||
barmode: 'group'
|
||||
hovermode: 'closest'
|
||||
};
|
||||
|
||||
Plotly.newPlot(chartDiv, data, layout, {responsive: true});
|
||||
|
|
@ -974,7 +1027,7 @@
|
|||
});
|
||||
}
|
||||
|
||||
function createSummaryPanel(positions, currentTick) {
|
||||
function createSummaryPanel(positions, currentTick, token0isWeth) {
|
||||
const panel = document.createElement('div');
|
||||
panel.className = 'summary-panel';
|
||||
|
||||
|
|
@ -1010,13 +1063,15 @@
|
|||
// Calculate position-specific liquidity percentage
|
||||
const liquidityPercent = totalUniV3Liquidity > 0 ? (pos.liquidity / totalUniV3Liquidity * 100).toFixed(1) : '0.0';
|
||||
const tickRange = pos.tickUpper - pos.tickLower;
|
||||
const lowerMultiple = tickToPriceMultiple(pos.tickLower, currentTick, token0isWeth);
|
||||
const upperMultiple = tickToPriceMultiple(pos.tickUpper, currentTick, token0isWeth);
|
||||
|
||||
item.innerHTML = `
|
||||
<strong>${pos.name} Position</strong><br>
|
||||
ETH: ${pos.eth.toLocaleString(undefined, {minimumFractionDigits: 6, maximumFractionDigits: 6})}<br>
|
||||
KRAIKEN: ${pos.kraiken.toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2})}<br>
|
||||
Uniswap V3 Liquidity: ${pos.liquidity.toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2})} (${liquidityPercent}%)<br>
|
||||
Range: ${tickRange} ticks
|
||||
Range: ${lowerMultiple.toFixed(3)}x - ${upperMultiple.toFixed(3)}x
|
||||
`;
|
||||
grid.appendChild(item);
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue