fix: pyproject.toml, module paths

This commit is contained in:
smypmsa
2025-03-17 15:47:28 +00:00
parent 396e9bce1d
commit 684b1c4b61
14 changed files with 72 additions and 56 deletions
View File
+130
View File
@@ -0,0 +1,130 @@
#!/usr/bin/env python3
"""
Command-line interface for the pump.fun trading bot.
"""
import argparse
import asyncio
import os
import sys
import config as config
from trading.trader import PumpTrader
from utils.logger import get_logger, setup_file_logging
logger = get_logger(__name__)
def parse_args() -> argparse.Namespace:
"""Parse command line arguments.
Returns:
Parsed arguments
"""
parser = argparse.ArgumentParser(description="Trade tokens on pump.fun.")
parser.add_argument(
"--yolo", action="store_true", help="Run in YOLO mode (continuous trading)"
)
parser.add_argument(
"--match",
type=str,
help="Only trade tokens with names or symbols matching this string",
)
parser.add_argument(
"--bro", type=str, help="Only trade tokens created by this user address"
)
parser.add_argument(
"--marry", action="store_true", help="Only buy tokens, skip selling"
)
parser.add_argument(
"--amount",
type=float,
help=f"Amount of SOL to spend on each buy (default: {config.BUY_AMOUNT})",
)
parser.add_argument(
"--buy-slippage",
type=float,
help=f"Buy slippage tolerance (default: {config.BUY_SLIPPAGE})",
)
parser.add_argument(
"--sell-slippage",
type=float,
help=f"Sell slippage tolerance (default: {config.SELL_SLIPPAGE})",
)
return parser.parse_args()
async def main() -> None:
"""Main entry point for the CLI."""
setup_file_logging("pump_trading.log")
args = parse_args()
# Get configuration values, preferring command line args over config.py
rpc_endpoint: str | None = os.environ.get("SOLANA_NODE_RPC_ENDPOINT")
wss_endpoint: str | None = os.environ.get("SOLANA_NODE_WSS_ENDPOINT")
private_key: str | None = os.environ.get("SOLANA_PRIVATE_KEY")
# Validate configuration values
if not rpc_endpoint or not rpc_endpoint.startswith(("http://", "https://")):
logger.error("Invalid RPC endpoint. Must start with http:// or https://")
sys.exit(1)
if not wss_endpoint or not wss_endpoint.startswith(("ws://", "wss://")):
logger.error("Invalid WebSocket endpoint. Must start with ws:// or wss://")
sys.exit(1)
if not private_key or len(private_key) < 80:
logger.error("Invalid private key. Key appears to be missing or too short")
sys.exit(1)
# Get trading parameters
buy_amount: float = args.amount if args.amount is not None else config.BUY_AMOUNT
buy_slippage: float = (
args.buy_slippage if args.buy_slippage is not None else config.BUY_SLIPPAGE
)
sell_slippage: float = (
args.sell_slippage if args.sell_slippage is not None else config.SELL_SLIPPAGE
)
# Not implemented parameters
enable_dynamic_prior__fee = (
config.ENABLE_DYNAMIC_PRIORITY_FEE
) # TODO: to be implemented
prior_fee_multiplier = config.EXTRA_PRIORITY_FEE # TODO: to be implemented
trader: PumpTrader = PumpTrader(
rpc_endpoint=rpc_endpoint, # type: ignore
wss_endpoint=wss_endpoint, # type: ignore
private_key=private_key,
buy_amount=buy_amount,
buy_slippage=buy_slippage,
sell_slippage=sell_slippage,
max_retries=config.MAX_RETRIES,
)
try:
await trader.start(
match_string=args.match,
bro_address=args.bro,
marry_mode=args.marry,
yolo_mode=args.yolo,
)
except KeyboardInterrupt:
logger.info("Trading stopped by user")
except Exception as e:
logger.error(f"Trading stopped due to error: {str(e)}")
finally:
try:
await trader.solana_client.close()
except Exception:
pass
def sync_main():
asyncio.run(main())
if __name__ == "__main__":
asyncio.run(main())
+68
View File
@@ -0,0 +1,68 @@
"""
Configuration for the pump.fun trading bot.
"""
# Trading parameters
BUY_AMOUNT: int | float = 0.000_001 # Amount of SOL to spend when buying
BUY_SLIPPAGE: float = 0.4 # 40% slippage tolerance for buying
SELL_SLIPPAGE: float = 0.4 # 40% slippage tolerance for selling
# Configuration for priority fee settings
ENABLE_DYNAMIC_PRIORITY_FEE: bool = False # Enable dynamic priority fee calculation
ENABLE_FIXED_PRIORITY_FEE: bool = True # Enable fixed priority fee
FIXED_PRIORITY_FEE: int = 2_000 # Fixed priority fee in microlamports
EXTRA_PRIORITY_FEE: float = (
0.0 # Percentage increase applied to priority fee (0.1 = 10%)
)
HARD_CAP_PRIOR_FEE: int = (
200_000 # Maximum allowed priority fee in microlamports (hard cap)
)
# Retries and timeouts
MAX_RETRIES: int = 10 # Number of retries for transaction sending
# TODO: waiting times will be replaced with retries to shorten delays
WAIT_TIME_AFTER_CREATION: int | float = (
15 # Time to wait after token creation (in seconds)
# Too short a delay may cause the RPC node to be unaware of the bonding curve account
)
WAIT_TIME_AFTER_BUY: int | float = (
15 # Time to wait after a buy transaction is confirmed (in seconds)
# Acts as a simple holding period
# Too short delay may cause the RPC node to be unaware of account balance
)
WAIT_TIME_BEFORE_NEW_TOKEN: int | float = (
5 # Time to wait after a sell transaction is confirmed (in seconds)
# Provides a pause between completed trades, can be set to 0
)
# Maximum age (in seconds) for a token to be considered "fresh" and eligible for processing.
# This threshold is checked before processing starts - tokens older than this are skipped
# since they likely contain outdated information from the websocket stream
MAX_TOKEN_AGE: int | float = 0.1
# Node provider configuration
# Tested with Chainstack nodes (https://console.chainstack.com), but you can use any node provider
# You can get a trader node https://docs.chainstack.com/docs/solana-trader-nodes
MAX_RPS: int = 25 # TODO: not implemented. Max RPS to avoid rate limit errors
def validate_priority_fee_config() -> None:
"""Validate priority fee configuration values."""
if not isinstance(ENABLE_DYNAMIC_PRIORITY_FEE, bool):
raise ValueError("ENABLE_DYNAMIC_PRIORITY_FEE must be a boolean")
if not isinstance(ENABLE_FIXED_PRIORITY_FEE, bool):
raise ValueError("ENABLE_FIXED_PRIORITY_FEE must be a boolean")
if not isinstance(FIXED_PRIORITY_FEE, int) or FIXED_PRIORITY_FEE < 0:
raise ValueError("FIXED_PRIORITY_FEE must be a non-negative integer")
if not isinstance(EXTRA_PRIORITY_FEE, float) or EXTRA_PRIORITY_FEE < 0:
raise ValueError("EXTRA_PRIORITY_FEE must be a non-negative float")
if not isinstance(HARD_CAP_PRIOR_FEE, int) or HARD_CAP_PRIOR_FEE < 0:
raise ValueError("HARD_CAP_PRIOR_FEE must be a non-negative integer")
# Validate config on import
validate_priority_fee_config()
+1 -1
View File
@@ -18,7 +18,7 @@ from solders.message import Message
from solders.pubkey import Pubkey
from solders.transaction import Transaction
from src.utils.logger import get_logger
from utils.logger import get_logger
logger = get_logger(__name__)
+3 -3
View File
@@ -8,9 +8,9 @@ from typing import Final
from construct import Flag, Int64ul, Struct
from solders.pubkey import Pubkey
from src.core.client import SolanaClient
from src.core.pubkeys import LAMPORTS_PER_SOL, TOKEN_DECIMALS
from src.utils.logger import get_logger
from core.client import SolanaClient
from core.pubkeys import LAMPORTS_PER_SOL, TOKEN_DECIMALS
from utils.logger import get_logger
logger = get_logger(__name__)
+2 -2
View File
@@ -2,9 +2,9 @@ import statistics
from solders.pubkey import Pubkey
from core.client import SolanaClient
from core.priority_fee import PriorityFeePlugin
from src.core.client import SolanaClient
from src.utils.logger import get_logger
from utils.logger import get_logger
logger = get_logger(__name__)
+4 -4
View File
@@ -1,9 +1,9 @@
from solders.pubkey import Pubkey
from src.core.client import SolanaClient
from src.core.priority_fee.dynamic_fee import DynamicPriorityFee
from src.core.priority_fee.fixed_fee import FixedPriorityFee
from src.utils.logger import get_logger
from core.client import SolanaClient
from core.priority_fee.dynamic_fee import DynamicPriorityFee
from core.priority_fee.fixed_fee import FixedPriorityFee
from utils.logger import get_logger
logger = get_logger(__name__)
+6 -6
View File
@@ -9,18 +9,18 @@ from solders.instruction import AccountMeta, Instruction
from solders.pubkey import Pubkey
from spl.token.instructions import create_associated_token_account
from core.client import SolanaClient
from core.curve import BondingCurveManager
from core.priority_fee.manager import PriorityFeeManager
from src.core.client import SolanaClient
from src.core.curve import BondingCurveManager
from src.core.pubkeys import (
from core.pubkeys import (
LAMPORTS_PER_SOL,
TOKEN_DECIMALS,
PumpAddresses,
SystemAddresses,
)
from src.core.wallet import Wallet
from src.trading.base import TokenInfo, Trader, TradeResult
from src.utils.logger import get_logger
from core.wallet import Wallet
from trading.base import TokenInfo, Trader, TradeResult
from utils.logger import get_logger
logger = get_logger(__name__)
+6 -6
View File
@@ -8,18 +8,18 @@ from typing import Final
from solders.instruction import AccountMeta, Instruction
from solders.pubkey import Pubkey
from core.client import SolanaClient
from core.curve import BondingCurveManager
from core.priority_fee.manager import PriorityFeeManager
from src.core.client import SolanaClient
from src.core.curve import BondingCurveManager
from src.core.pubkeys import (
from core.pubkeys import (
LAMPORTS_PER_SOL,
TOKEN_DECIMALS,
PumpAddresses,
SystemAddresses,
)
from src.core.wallet import Wallet
from src.trading.base import TokenInfo, Trader, TradeResult
from src.utils.logger import get_logger
from core.wallet import Wallet
from trading.base import TokenInfo, Trader, TradeResult
from utils.logger import get_logger
logger = get_logger(__name__)
+10 -10
View File
@@ -8,17 +8,17 @@ import json
import os
from datetime import datetime
import config
import config as config
from core.client import SolanaClient
from core.curve import BondingCurveManager
from core.priority_fee.manager import PriorityFeeManager
from src.core.client import SolanaClient
from src.core.curve import BondingCurveManager
from src.core.pubkeys import PumpAddresses
from src.core.wallet import Wallet
from src.monitoring.listener import PumpTokenListener
from src.trading.base import TokenInfo, TradeResult
from src.trading.buyer import TokenBuyer
from src.trading.seller import TokenSeller
from src.utils.logger import get_logger
from core.pubkeys import PumpAddresses
from core.wallet import Wallet
from monitoring.listener import PumpTokenListener
from trading.base import TokenInfo, TradeResult
from trading.buyer import TokenBuyer
from trading.seller import TokenSeller
from utils.logger import get_logger
logger = get_logger(__name__)