feat: full project overhaul — market maker, sniper, WebSocket watcher, terminal UI
- Rename project to polymarket-terminal - Add Market Maker bot (src/mm.js) with on-chain CTF split/merge/redeem via Gnosis Safe - Add Orderbook Sniper bot (src/sniper.js) with multi-asset GTC low-price orders - Add WebSocket watcher (src/services/wsWatcher.js) for real-time RTDS trade events - Add terminal dashboard UI (src/ui/dashboard.js) using blessed - Add CTF contract helpers (src/services/ctf.js) for splitPosition, mergePositions, redeemPositions - Add mmDetector, mmExecutor, sniperDetector, sniperExecutor services - Add simStats utility for dry-run P&L tracking - Translate all Indonesian-language strings to professional English across all files - Rewrite README.md in English with full setup guide, configuration reference, and architecture overview - Rewrite AGENT.MD in English as comprehensive AI agent and developer reference - Update package.json name, description, scripts, and keywords Co-Authored-By: direkturcrypto <direkturcrypto.x@mail3.me>
This commit is contained in:
+47
-6
@@ -3,8 +3,8 @@ dotenv.config();
|
||||
|
||||
const config = {
|
||||
// Wallet
|
||||
privateKey: process.env.PRIVATE_KEY,
|
||||
walletAddress: process.env.WALLET_ADDRESS,
|
||||
privateKey: process.env.PRIVATE_KEY, // EOA private key (for signing only)
|
||||
proxyWallet: process.env.PROXY_WALLET_ADDRESS, // Polymarket proxy wallet (deposit USDC here)
|
||||
|
||||
// Polymarket API (optional, auto-derived if empty)
|
||||
clobApiKey: process.env.CLOB_API_KEY || '',
|
||||
@@ -17,6 +17,9 @@ const config = {
|
||||
dataHost: 'https://data-api.polymarket.com',
|
||||
chainId: 137,
|
||||
|
||||
// Polygon RPC
|
||||
polygonRpcUrl: process.env.POLYGON_RPC_URL || 'https://polygon-bor-rpc.publicnode.com',
|
||||
|
||||
// Trader to copy
|
||||
traderAddress: process.env.TRADER_ADDRESS,
|
||||
|
||||
@@ -24,6 +27,7 @@ const config = {
|
||||
sizeMode: process.env.SIZE_MODE || 'percentage', // "percentage" | "balance"
|
||||
sizePercent: parseFloat(process.env.SIZE_PERCENT || '50'),
|
||||
minTradeSize: parseFloat(process.env.MIN_TRADE_SIZE || '1'),
|
||||
maxPositionSize: parseFloat(process.env.MAX_POSITION_SIZE || '10'),
|
||||
|
||||
// Auto sell
|
||||
autoSellEnabled: process.env.AUTO_SELL_ENABLED === 'true',
|
||||
@@ -32,8 +36,7 @@ const config = {
|
||||
// Sell mode when copying sell
|
||||
sellMode: process.env.SELL_MODE || 'market', // "market" | "limit"
|
||||
|
||||
// Polling intervals (seconds)
|
||||
pollInterval: parseInt(process.env.POLL_INTERVAL || '15', 10) * 1000,
|
||||
// Redeem interval (seconds)
|
||||
redeemInterval: parseInt(process.env.REDEEM_INTERVAL || '60', 10) * 1000,
|
||||
|
||||
// Dry run
|
||||
@@ -42,11 +45,37 @@ const config = {
|
||||
// Retry settings
|
||||
maxRetries: 5,
|
||||
retryDelay: 3000,
|
||||
|
||||
// ── Market Maker ──────────────────────────────────────────────
|
||||
mmAssets: (process.env.MM_ASSETS || 'btc')
|
||||
.split(',').map((s) => s.trim().toLowerCase()).filter(Boolean),
|
||||
mmDuration: process.env.MM_DURATION || '5m', // '5m' or '15m'
|
||||
mmTradeSize: parseFloat(process.env.MM_TRADE_SIZE || '5'), // USDC per side
|
||||
mmSellPrice: parseFloat(process.env.MM_SELL_PRICE || '0.60'), // limit sell target
|
||||
mmCutLossTime: parseInt( process.env.MM_CUT_LOSS_TIME || '60', 10), // seconds before close
|
||||
mmMarketKeyword: process.env.MM_MARKET_KEYWORD || 'Bitcoin Up or Down',
|
||||
mmEntryWindow: parseInt( process.env.MM_ENTRY_WINDOW || '45', 10), // max secs after open
|
||||
mmPollInterval: parseInt( process.env.MM_POLL_INTERVAL || '10', 10) * 1000,
|
||||
|
||||
// ── Recovery Buy (after cut-loss) ─────────────────────────────
|
||||
// When enabled: after cutting loss, monitor prices for 10s and
|
||||
// market-buy the dominant side if it's above threshold and rising/stable.
|
||||
mmRecoveryBuy: process.env.MM_RECOVERY_BUY === 'true',
|
||||
mmRecoveryThreshold: parseFloat(process.env.MM_RECOVERY_THRESHOLD || '0.70'), // min price to qualify
|
||||
mmRecoverySize: parseFloat(process.env.MM_RECOVERY_SIZE || '0'), // 0 = use mmTradeSize
|
||||
|
||||
// ── Orderbook Sniper ───────────────────────────────────────────
|
||||
// Places tiny GTC limit BUY orders at a very low price on each side
|
||||
// of ETH/SOL/XRP 5-minute markets — catches panic dumps near $0.
|
||||
sniperAssets: (process.env.SNIPER_ASSETS || 'eth,sol,xrp')
|
||||
.split(',').map((s) => s.trim().toLowerCase()).filter(Boolean),
|
||||
sniperPrice: parseFloat(process.env.SNIPER_PRICE || '0.01'), // $ per share
|
||||
sniperShares: parseFloat(process.env.SNIPER_SHARES || '5'), // shares per side
|
||||
};
|
||||
|
||||
// Validation
|
||||
// Validation for copy-trade bot
|
||||
export function validateConfig() {
|
||||
const required = ['privateKey', 'walletAddress', 'traderAddress'];
|
||||
const required = ['privateKey', 'proxyWallet', 'traderAddress'];
|
||||
const missing = required.filter((key) => !config[key]);
|
||||
if (missing.length > 0) {
|
||||
throw new Error(`Missing required config: ${missing.join(', ')}. Check your .env file.`);
|
||||
@@ -59,4 +88,16 @@ export function validateConfig() {
|
||||
}
|
||||
}
|
||||
|
||||
// Validation for market-maker bot
|
||||
export function validateMMConfig() {
|
||||
const required = ['privateKey', 'proxyWallet'];
|
||||
const missing = required.filter((key) => !config[key]);
|
||||
if (missing.length > 0) {
|
||||
throw new Error(`Missing required config: ${missing.join(', ')}. Check your .env file.`);
|
||||
}
|
||||
if (config.mmTradeSize <= 0) throw new Error('MM_TRADE_SIZE must be > 0');
|
||||
if (config.mmSellPrice <= 0 || config.mmSellPrice >= 1)
|
||||
throw new Error('MM_SELL_PRICE must be between 0 and 1');
|
||||
}
|
||||
|
||||
export default config;
|
||||
|
||||
Reference in New Issue
Block a user