Fix ETH openPosition
This commit is contained in:
@@ -170,7 +170,8 @@ public class TradingBotBase : ITradingBot
|
|||||||
{
|
{
|
||||||
ExecutionCount++;
|
ExecutionCount++;
|
||||||
|
|
||||||
Logger.LogInformation("Bot Status - ServerDate: {ServerDate}, LastCandleDate: {LastCandleDate}, Signals: {SignalCount}, Executions: {ExecutionCount}, Positions: {PositionCount}",
|
Logger.LogInformation(
|
||||||
|
"Bot Status - ServerDate: {ServerDate}, LastCandleDate: {LastCandleDate}, Signals: {SignalCount}, Executions: {ExecutionCount}, Positions: {PositionCount}",
|
||||||
DateTime.UtcNow, LastCandle.Date, Signals.Count, ExecutionCount, Positions.Count);
|
DateTime.UtcNow, LastCandle.Date, Signals.Count, ExecutionCount, Positions.Count);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1444,6 +1445,8 @@ public class TradingBotBase : ITradingBot
|
|||||||
TradingExchanges.GmxV2,
|
TradingExchanges.GmxV2,
|
||||||
IndicatorType.Stc, SignalType.Signal, "Manual Signal");
|
IndicatorType.Stc, SignalType.Signal, "Manual Signal");
|
||||||
signal.Status = SignalStatus.WaitingForPosition; // Ensure status is correct
|
signal.Status = SignalStatus.WaitingForPosition; // Ensure status is correct
|
||||||
|
signal.Identifier =
|
||||||
|
signal.Identifier + "-manual" + Guid.NewGuid(); // Ensure unique identifier for manual signals
|
||||||
|
|
||||||
// Add the signal to our collection
|
// Add the signal to our collection
|
||||||
await AddSignal(signal);
|
await AddSignal(signal);
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ public class LightSignal
|
|||||||
|
|
||||||
[Id(5)] [Required] public Candle Candle { get; }
|
[Id(5)] [Required] public Candle Candle { get; }
|
||||||
|
|
||||||
[Id(6)] [Required] public string Identifier { get; }
|
[Id(6)] [Required] public string Identifier { get; set; }
|
||||||
|
|
||||||
[Id(7)] [Required] public Ticker Ticker { get; }
|
[Id(7)] [Required] public Ticker Ticker { get; }
|
||||||
|
|
||||||
|
|||||||
@@ -294,8 +294,19 @@ export const openGmxPositionImpl = async (
|
|||||||
const marketInfo = getMarketInfoFromTicker(ticker, marketsInfoData);
|
const marketInfo = getMarketInfoFromTicker(ticker, marketsInfoData);
|
||||||
const collateralToken = getTokenDataFromTicker("USDC", tokensData); // Using USDC as collateral
|
const collateralToken = getTokenDataFromTicker("USDC", tokensData); // Using USDC as collateral
|
||||||
|
|
||||||
|
// For market orders, we need to get the current market price
|
||||||
|
let currentPrice = price;
|
||||||
|
if (!currentPrice) {
|
||||||
|
// Get current market price from market info
|
||||||
|
currentPrice = Number(marketInfo.indexToken.prices.minPrice) / 1e30; // Convert from 30 decimals
|
||||||
|
console.log(`No price provided, using current market price: ${currentPrice}`);
|
||||||
|
}
|
||||||
|
|
||||||
// Calculate the collateral amount in USDC (quantity * price)
|
// Calculate the collateral amount in USDC (quantity * price)
|
||||||
const collateralAmount = BigInt(Math.floor((quantity || 0) * (price || 0) * 1e6)); // USDC has 6 decimals
|
const collateralAmount = BigInt(Math.floor((quantity || 0) * currentPrice * 1e6)); // USDC has 6 decimals
|
||||||
|
|
||||||
|
// Note: Wallet initialization should be done separately before opening positions
|
||||||
|
// This reduces position opening time and allows for better error handling
|
||||||
|
|
||||||
// Calculate leverage in basis points (1x = 10000)
|
// Calculate leverage in basis points (1x = 10000)
|
||||||
const leverageBps = BigInt((leverage || 1) * 10000);
|
const leverageBps = BigInt((leverage || 1) * 10000);
|
||||||
@@ -316,11 +327,23 @@ export const openGmxPositionImpl = async (
|
|||||||
limitPrice: limitPrice,
|
limitPrice: limitPrice,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
console.log('📋 Position params:', {
|
||||||
|
payAmount: collateralAmount.toString(),
|
||||||
|
marketAddress: marketInfo.marketTokenAddress,
|
||||||
|
payTokenAddress: collateralToken.address,
|
||||||
|
collateralTokenAddress: collateralToken.address,
|
||||||
|
leverage: leverageBps.toString(),
|
||||||
|
direction: direction
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log('🚀 Executing position order...');
|
||||||
|
|
||||||
if (direction === TradeDirection.Long) {
|
if (direction === TradeDirection.Long) {
|
||||||
await sdk.orders.long(params);
|
await sdk.orders.long(params);
|
||||||
} else {
|
} else {
|
||||||
await sdk.orders.short(params);
|
await sdk.orders.short(params);
|
||||||
}
|
}
|
||||||
|
console.log('✅ Position order executed successfully');
|
||||||
|
|
||||||
return "";
|
return "";
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -485,12 +508,23 @@ export async function cancelGmxOrders(
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getMarketInfoFromTicker(ticker: string, marketsInfoData: MarketsInfoData): MarketInfo {
|
function getMarketInfoFromTicker(ticker: string, marketsInfoData: MarketsInfoData): MarketInfo {
|
||||||
|
if (ticker === "ETH") {
|
||||||
|
ticker = "WETH";
|
||||||
|
}
|
||||||
|
|
||||||
const token = getTokenBySymbol(arbitrum.id, ticker);
|
const token = getTokenBySymbol(arbitrum.id, ticker);
|
||||||
const marketInfo = getMarketByIndexToken(token.address);
|
const marketInfo = getMarketByIndexToken(token.address);
|
||||||
const marketInfoData = marketsInfoData[marketInfo.marketTokenAddress];
|
|
||||||
if (!marketInfo) {
|
if (!marketInfo) {
|
||||||
throw new Error(`Market info not found for ticker: ${ticker}`);
|
throw new Error(`Market info not found for ticker: ${ticker}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const marketInfoData = marketsInfoData[marketInfo.marketTokenAddress];
|
||||||
|
|
||||||
|
if (!marketInfoData) {
|
||||||
|
throw new Error(`Market data not found for market: ${marketInfo.marketTokenAddress}`);
|
||||||
|
}
|
||||||
|
|
||||||
return marketInfoData;
|
return marketInfoData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -501,30 +501,31 @@ export const getTokenAllowance = async (
|
|||||||
*/
|
*/
|
||||||
export const initAddressImpl = async (
|
export const initAddressImpl = async (
|
||||||
address: string,
|
address: string,
|
||||||
): Promise<{ usdcHash: string, orderVaultHash: string, exchangeRouterHash: string }> => {
|
): Promise<{ usdcHash: string, orderVaultHash: string, exchangeRouterHash: string, wethSyntheticsRouterHash: string }> => {
|
||||||
try {
|
try {
|
||||||
const sdk = await getClientForAddress(address);
|
const sdk = await getClientForAddress(address);
|
||||||
|
|
||||||
const {tokensData} = await sdk.tokens.getTokensData();
|
const {tokensData} = await sdk.tokens.getTokensData();
|
||||||
const usdcTokenData = getTokenDataFromTicker(Ticker.USDC, tokensData);
|
const usdcTokenData = getTokenDataFromTicker(Ticker.USDC, tokensData);
|
||||||
const wrapperEtherData = getTokenDataFromTicker("WETH", tokensData);
|
const wrapperEtherData = getTokenDataFromTicker("WETH", tokensData);
|
||||||
let approveAmount = usdcTokenData.prices.maxPrice; // Large enough amount for trading
|
|
||||||
|
// Use max uint256 for unlimited approvals (more gas efficient than frequent approvals)
|
||||||
|
let approveAmount = BigInt("115792089237316195423570985008687907853269984665640564039457584007913129639935");
|
||||||
|
|
||||||
// Check approval for USDC
|
// Check approval for USDC (this first check is for general token approval, keeping original logic)
|
||||||
const usdcToken = GetToken('USDC');
|
const usdcToken = GetToken('USDC');
|
||||||
const usdcAllowance = await getTokenAllowance(address, usdcToken.address, address);
|
const usdcAllowance = await getTokenAllowance(address, usdcToken.address, address);
|
||||||
|
|
||||||
let usdcHash = "";
|
let usdcHash = "";
|
||||||
if (usdcAllowance < approveAmount) {
|
if (usdcAllowance < approveAmount) {
|
||||||
// First approve USDC token for GMX trading
|
// First approve USDC token for GMX trading
|
||||||
const usdcToken = GetToken('USDC');
|
|
||||||
usdcHash = await approveTokenImpl(
|
usdcHash = await approveTokenImpl(
|
||||||
address,
|
address,
|
||||||
usdcToken.symbol,
|
usdcToken.symbol,
|
||||||
ARBITRUM,
|
ARBITRUM,
|
||||||
usdcTokenData.prices.maxPrice
|
usdcTokenData.prices.maxPrice
|
||||||
);
|
);
|
||||||
}else{
|
} else {
|
||||||
usdcHash = "Already allowed :" + usdcAllowance;
|
usdcHash = "Already allowed :" + usdcAllowance;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -612,14 +613,34 @@ export const initAddressImpl = async (
|
|||||||
|
|
||||||
console.log('usdcSyntheticRouterAllowance', usdcSyntheticRouterAllowance)
|
console.log('usdcSyntheticRouterAllowance', usdcSyntheticRouterAllowance)
|
||||||
|
|
||||||
|
// Also approve WETH for SyntheticsRouter (required for ETH positions)
|
||||||
|
const wethSyntheticsRouterAllowance = await getTokenAllowance(address, wrapperEtherData.address, CONTRACTS[ARBITRUM].SyntheticsRouter);
|
||||||
|
|
||||||
|
let wethSyntheticsRouterHash = "";
|
||||||
|
if (wethSyntheticsRouterAllowance < approveAmount) {
|
||||||
|
wethSyntheticsRouterHash = await approveContractImpl(
|
||||||
|
address,
|
||||||
|
wrapperEtherData.address,
|
||||||
|
CONTRACTS[ARBITRUM].SyntheticsRouter,
|
||||||
|
ARBITRUM,
|
||||||
|
approveAmount
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
wethSyntheticsRouterHash = "Already allowed :" + wethSyntheticsRouterAllowance;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('wethSyntheticsRouterAllowance', wethSyntheticsRouterAllowance)
|
||||||
|
|
||||||
console.log('usdcHash', usdcHash)
|
console.log('usdcHash', usdcHash)
|
||||||
console.log('orderVaultHash', orderVaultHash)
|
console.log('orderVaultHash', orderVaultHash)
|
||||||
console.log('exchangeRouterHash', exchangeRouterHash)
|
console.log('exchangeRouterHash', exchangeRouterHash)
|
||||||
|
console.log('wethSyntheticsRouterHash', wethSyntheticsRouterHash)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
usdcHash,
|
usdcHash,
|
||||||
orderVaultHash,
|
orderVaultHash,
|
||||||
exchangeRouterHash
|
exchangeRouterHash,
|
||||||
|
wethSyntheticsRouterHash
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error initializing address:', error);
|
console.error('Error initializing address:', error);
|
||||||
@@ -644,12 +665,14 @@ export async function initAddress(
|
|||||||
throw new Error('Wallet address is required for initialization');
|
throw new Error('Wallet address is required for initialization');
|
||||||
}
|
}
|
||||||
|
|
||||||
const { usdcHash, orderVaultHash } = await initAddressImpl(address);
|
const { usdcHash, orderVaultHash, exchangeRouterHash, wethSyntheticsRouterHash } = await initAddressImpl(address);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
success: true,
|
success: true,
|
||||||
usdcHash,
|
usdcHash,
|
||||||
orderVaultHash
|
orderVaultHash,
|
||||||
|
exchangeRouterHash,
|
||||||
|
wethSyntheticsRouterHash
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.log.error(error);
|
this.log.error(error);
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { test } from 'node:test'
|
import {test} from 'node:test'
|
||||||
import assert from 'node:assert'
|
import assert from 'node:assert'
|
||||||
import { getClientForAddress, openGmxPositionImpl } from '../../src/plugins/custom/gmx'
|
import {getClientForAddress, openGmxPositionImpl} from '../../src/plugins/custom/gmx'
|
||||||
import { Ticker, TradeDirection } from '../../src/generated/ManagingApiTypes'
|
import {Ticker, TradeDirection} from '../../src/generated/ManagingApiTypes'
|
||||||
|
|
||||||
test('GMX Position Opening', async (t) => {
|
test('GMX Position Opening', async (t) => {
|
||||||
await t.test('should open a long position for BTC', async () => {
|
await t.test('should open a long position for BTC', async () => {
|
||||||
@@ -9,13 +9,13 @@ test('GMX Position Opening', async (t) => {
|
|||||||
|
|
||||||
const result = await openGmxPositionImpl(
|
const result = await openGmxPositionImpl(
|
||||||
sdk,
|
sdk,
|
||||||
Ticker.BTC,
|
Ticker.ETH,
|
||||||
TradeDirection.Long,
|
TradeDirection.Long,
|
||||||
0.0002,
|
0.00678,
|
||||||
2,
|
2,
|
||||||
50003,
|
4400,
|
||||||
96001,
|
6000,
|
||||||
85002
|
3500
|
||||||
)
|
)
|
||||||
console.log('Position opening result:', result)
|
console.log('Position opening result:', result)
|
||||||
assert.ok(result, 'Position opening result should be defined')
|
assert.ok(result, 'Position opening result should be defined')
|
||||||
|
|||||||
Reference in New Issue
Block a user