refactor: split PM2 ecosystem config into pm2/ folder + update README

- ecosystem.config.cjs removed from root
- pm2/copy.config.cjs — copy trade bot config
- pm2/mm.config.cjs   — market maker bot config
  Both use __dirname-relative paths so they work regardless of cwd.

README updated:
- Added PM2/VPS section with per-bot start/log/management commands
- Added plain log mode section (bot / mm-bot scripts)
- Updated project structure tree with new files
- Added MIN_MARKET_TIME_LEFT and GTC_FALLBACK_TIMEOUT to config table
- Updated copy trade flow diagram

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
direkturcrypto
2026-02-26 02:11:20 +07:00
parent 5ea7f3d2b0
commit f4490c12ac
4 changed files with 230 additions and 141 deletions
+136 -60
View File
@@ -13,37 +13,38 @@
- [Installation](#installation)
- [Configuration](#configuration)
- [Usage](#usage)
- [Running on VPS with PM2](#running-on-vps-with-pm2)
- [How It Works](#how-it-works)
- [Project Structure](#project-structure)
- [Important Warnings](#important-warnings)
- [Contributing](#contributing)
- [License](#license)
---
## Features
### Copy Trade Bot (`npm start`)
### Copy Trade Bot
- **Watch Trader** — Monitor any Polymarket wallet address in real time via WebSocket
- **Copy Buy** — Automatically mirror buy orders with configurable position sizing
- **Copy Sell** — Automatically mirror sell orders (market or limit)
- **Auto Sell** — Place a GTC limit sell at a target profit % immediately after a buy fills
- **Auto Redeem** — Periodically check and redeem winning positions on-chain
- **Deduplication** — Each market is entered at most once; no double buys
- **Balance Guard** — Checks USDC.e balance before every order
- **Market Expiry Guard** — Skip buys if market closes within `MIN_MARKET_TIME_LEFT` seconds
- **GTC Fallback** — Falls back to a GTC limit order when copying "next market" trades with no liquidity
- **Per-Market Queue** — Concurrent events for the same market are serialized to prevent duplicate buys
- **Dry Run Mode** — Simulate the full flow without placing real orders
### Market Maker Bot (`npm run mm`)
### Market Maker Bot
- **Automated Liquidity** — Splits USDC into YES+NO tokens and places limit sells on both sides at $0.50 entry
- **Cut-Loss Protection** — Merges unsold tokens back to USDC before market close
- **Recovery Buy** — Optional directional bet after a cut-loss triggers
- **Multi-Asset** — Supports BTC, ETH, SOL, and any 5m/15m Polymarket market
- **Simulation Mode** — Full dry-run with P&L tracking (`npm run mm-sim`)
- **Simulation Mode** — Full dry-run with P&L tracking
### Orderbook Sniper Bot (`npm run sniper`)
### Orderbook Sniper Bot
- **Low-Price Orders** — Places tiny GTC BUY orders at a configurable price (e.g. $0.01) on both sides
- **Multi-Asset** — Targets ETH, SOL, XRP, and more simultaneously
- **Simulation Mode** — Preview orders without spending funds (`npm run sniper-sim`)
- **Simulation Mode** — Preview orders without spending funds
---
@@ -56,6 +57,7 @@
| Polymarket Proxy Wallet | Your proxy wallet address (visible on your Polymarket profile → Deposit) |
| USDC.e on Polygon | Deposited via Polymarket's deposit flow |
| MATIC on Polygon | A small amount for gas fees (redeem & on-chain operations) |
| PM2 *(optional)* | For running on a VPS: `npm install -g pm2` |
---
@@ -72,8 +74,8 @@ npm install
# 3. Copy the environment template
cp .env.example .env
# 4. Fill in your credentials (see Configuration section below)
nano .env # or use your preferred editor
# 4. Fill in your credentials
nano .env
```
---
@@ -115,6 +117,8 @@ Leave these blank to have the client auto-derive credentials from your private k
| `AUTO_SELL_PROFIT_PERCENT` | Target profit % for the auto-sell limit order | `10` |
| `SELL_MODE` | `market` or `limit` when copying a sell | `market` |
| `REDEEM_INTERVAL` | Seconds between redemption checks | `60` |
| `MIN_MARKET_TIME_LEFT` | Skip buy if market closes within this many seconds | `300` |
| `GTC_FALLBACK_TIMEOUT` | Seconds to wait for GTC fill when FAK finds no liquidity | `60` |
| `DRY_RUN` | Simulate without placing real orders | `true` |
### Market Maker Bot Settings
@@ -145,23 +149,100 @@ Leave these blank to have the client auto-derive credentials from your private k
## Usage
### Terminal UI (local)
Runs with an interactive split-panel dashboard (blessed TUI).
```bash
# ── Copy Trade Bot ─────────────────────────────────
npm start # Production mode
npm run dev # Development mode (auto-reload on file changes)
# Copy Trade Bot
npm start # live trading
npm run dev # live + auto-reload on file changes
# ── Market Maker Bot ───────────────────────────────
npm run mm # Live trading (DRY_RUN=false)
npm run mm-sim # Simulation mode (DRY_RUN=true)
npm run mm-dev # Simulation + auto-reload
# Market Maker Bot
npm run mm # live trading
npm run mm-sim # simulation (DRY_RUN=true)
npm run mm-dev # simulation + auto-reload
# ── Orderbook Sniper Bot ───────────────────────────
npm run sniper # Live trading (DRY_RUN=false)
npm run sniper-sim # Simulation mode (DRY_RUN=true)
npm run sniper-dev # Simulation + auto-reload
# Orderbook Sniper Bot
npm run sniper # live trading
npm run sniper-sim # simulation
npm run sniper-dev # simulation + auto-reload
```
> **Always test with `DRY_RUN=true` first** before committing real funds.
### Plain Log Mode (no TUI)
Writes plain timestamped text to stdout — suitable for piping, `tail -f`, or PM2.
```bash
# Copy Trade Bot
npm run bot # live trading
npm run bot-sim # simulation
npm run bot-dev # simulation + auto-reload
# Market Maker Bot
npm run mm-bot # live trading
npm run mm-bot-sim # simulation
npm run mm-bot-dev # simulation + auto-reload
```
> **Always test with `DRY_RUN=true` (or `*-sim` scripts) first** before committing real funds.
---
## Running on VPS with PM2
Each bot has its own PM2 config file inside the `pm2/` folder.
### Install PM2
```bash
npm install -g pm2
```
### Copy Trade Bot
```bash
# Live trading
pm2 start pm2/copy.config.cjs
# Simulation
pm2 start pm2/copy.config.cjs --env sim
# View logs
pm2 logs polymarket-copy
tail -f logs/copy-out.log
# Management
pm2 restart polymarket-copy
pm2 stop polymarket-copy
pm2 delete polymarket-copy
```
### Market Maker Bot
```bash
# Live trading
pm2 start pm2/mm.config.cjs
# Simulation
pm2 start pm2/mm.config.cjs --env sim
# View logs
pm2 logs polymarket-mm
tail -f logs/mm-out.log
# Management
pm2 restart polymarket-mm
pm2 stop polymarket-mm
pm2 delete polymarket-mm
```
### Auto-start on reboot
```bash
pm2 startup # generates a startup command — run the command it prints
pm2 save # saves current process list
```
---
@@ -170,24 +251,25 @@ npm run sniper-dev # Simulation + auto-reload
### Copy Trade Bot Flow
```
┌──────────────────────────────────────────────────────────┐
│ WATCHER LOOP
│ WebSocket (RTDS) — real-time trade events from trader │
│ Fallback: poll Data API every N seconds │
├───────────────────────┬──────────────────────────────────┤
│ NEW BUY │ NEW SELL │
│ │
│ ✓ Check position │ ✓ Check position exists │
✓ Check USDC balance │ ✓ Cancel existing auto-sell
│ ✓ Market buy (FOK) │ ✓ Market / limit sell │
│ ✓ Retry on failure │ ✓ Retry on failure │
│ ✓ Place auto-sell │ ✓ Remove position from state │
│ ✓ Save position │ │
├───────────────────────┴──────────────────────────────────┤
│ REDEEMER LOOP │
│ Periodically checks resolved markets
│ → Redeems winning positions via CTF contract on-chain │
└──────────────────────────────────────────────────────────┘
WebSocket (RTDS) — real-time trade events from trader
Per-market queue (prevents concurrent duplicate buys)
┌────┴──────┐
BUY SELL
├─ Expiry guard (MIN_MARKET_TIME_LEFT)
├─ Max position cap ├─ Cancel open orders
├─ FAK market buy ├─ Reconcile on-chain balance
│ └─ 0 fill? → GTC fallback ├─ FAK market sell / limit sell
├─ Place auto-sell GTC └─ Remove position
└─ Save position
Redeemer loop (every REDEEM_INTERVAL seconds)
→ Check on-chain payout → redeemPositions via Gnosis Safe
```
### Market Maker Flow
@@ -206,7 +288,7 @@ Monitor fills every few seconds
┌────┴────┐
│ │
Fill Time < MM_CUT_LOSS_TIME
Fill Time < MM_CUT_LOSS_TIME
│ │
▼ ▼
Collect Cancel orders → Merge YES+NO back to USDC
@@ -220,9 +302,11 @@ Collect Cancel orders → Merge YES+NO back to USDC
```
polymarket-terminal/
├── src/
│ ├── index.js — Copy trade bot entry point
│ ├── mm.js — Market maker bot entry point
│ ├── sniper.jsOrderbook sniper bot entry point
│ ├── index.js — Copy trade bot (TUI)
│ ├── bot.js — Copy trade bot (plain log / PM2)
│ ├── mm.js Market maker bot (TUI)
│ ├── mm-bot.js — Market maker bot (plain log / PM2)
│ ├── sniper.js — Orderbook sniper bot
│ │
│ ├── config/
│ │ └── index.js — Environment variable loading & validation
@@ -235,7 +319,7 @@ polymarket-terminal/
│ │ ├── position.js — Position state management (CRUD)
│ │ ├── autoSell.js — Auto limit-sell placement
│ │ ├── redeemer.js — Market resolution check & CTF redemption
│ │ ├── ctf.js — On-chain CTF contract interactions (MM bot)
│ │ ├── ctf.js — On-chain CTF contract interactions
│ │ ├── mmDetector.js — Market detection for market maker
│ │ ├── mmExecutor.js — Market maker strategy execution
│ │ ├── sniperDetector.js — Market detection for sniper
@@ -245,11 +329,16 @@ polymarket-terminal/
│ │ └── dashboard.js — Terminal UI (blessed)
│ │
│ └── utils/
│ ├── logger.js — Color-coded, timestamped logging
│ ├── logger.js — Timestamped logging (TUI + plain modes)
│ ├── state.js — Atomic JSON state file management
│ └── simStats.js — Simulation P&L statistics
├── pm2/
│ ├── copy.config.cjs — PM2 config for copy trade bot
│ └── mm.config.cjs — PM2 config for market maker bot
├── data/ — Runtime state files (gitignored)
├── logs/ — PM2 log files (gitignored)
├── .env.example — Configuration template
├── .gitignore
└── package.json
@@ -260,26 +349,13 @@ polymarket-terminal/
## Important Warnings
- **Never commit your `.env` file.** Your private key must remain secret. The `.gitignore` already excludes it.
- **Always start with `DRY_RUN=true`** to verify the bot behaves as expected before using real funds.
- **Always start with `DRY_RUN=true`** (or a `*-sim` script) to verify the bot behaves as expected before using real funds.
- **Use a small `SIZE_PERCENT`** for initial live runs to limit exposure.
- **Keep MATIC in your EOA wallet** for gas fees (redeem operations and on-chain CTF calls).
- **This software is provided as-is, with no guarantees.** Prediction market trading carries significant financial risk. You are solely responsible for any losses.
---
## Contributing
Contributions are welcome! To get started:
1. Fork the repository
2. Create a feature branch: `git checkout -b feat/your-feature`
3. Make your changes and ensure the code is clean and well-documented
4. Open a pull request describing what you changed and why
Please keep pull requests focused and avoid mixing unrelated changes.
---
## Credits
Built and maintained by **[@direkturcrypto](https://twitter.com/direkturcrypto)**.
-81
View File
@@ -1,81 +0,0 @@
/**
* PM2 ecosystem config
*
* Start all bots:
* pm2 start ecosystem.config.cjs # live trading
* pm2 start ecosystem.config.cjs --env sim # simulation / dry-run
*
* Start individual bot:
* pm2 start ecosystem.config.cjs --only polymarket-copy
* pm2 start ecosystem.config.cjs --only polymarket-mm
* pm2 start ecosystem.config.cjs --only polymarket-copy --env sim
* pm2 start ecosystem.config.cjs --only polymarket-mm --env sim
*
* Logs:
* pm2 logs # all bots
* pm2 logs polymarket-copy # copy trade only
* pm2 logs polymarket-mm # market maker only
* pm2 logs polymarket-copy --lines 200
*
* Management:
* pm2 restart / stop / delete polymarket-copy
* pm2 restart / stop / delete polymarket-mm
* pm2 restart all
*/
module.exports = {
apps: [
// ── Copy Trade Bot ─────────────────────────────────────────────────────
{
name: 'polymarket-copy',
script: 'src/bot.js',
interpreter: 'node',
env: {
NODE_ENV: 'production',
DRY_RUN: 'false',
},
env_sim: {
NODE_ENV: 'production',
DRY_RUN: 'true',
},
out_file: 'logs/copy-out.log',
error_file: 'logs/copy-error.log',
log_date_format: 'YYYY-MM-DD HH:mm:ss Z',
merge_logs: true,
restart_delay: 5000,
max_restarts: 10,
min_uptime: '10s',
max_memory_restart: '256M',
stop_exit_codes: [0],
},
// ── Market Maker Bot ───────────────────────────────────────────────────
{
name: 'polymarket-mm',
script: 'src/mm-bot.js',
interpreter: 'node',
env: {
NODE_ENV: 'production',
DRY_RUN: 'false',
},
env_sim: {
NODE_ENV: 'production',
DRY_RUN: 'true',
},
out_file: 'logs/mm-out.log',
error_file: 'logs/mm-error.log',
log_date_format: 'YYYY-MM-DD HH:mm:ss Z',
merge_logs: true,
restart_delay: 5000,
max_restarts: 10,
min_uptime: '10s',
max_memory_restart: '256M',
stop_exit_codes: [0],
},
],
};
+47
View File
@@ -0,0 +1,47 @@
/**
* PM2 config — Copy Trade Bot
*
* Usage (from project root):
* pm2 start pm2/copy.config.cjs # live trading
* pm2 start pm2/copy.config.cjs --env sim # simulation / dry-run
*
* pm2 logs polymarket-copy
* pm2 restart polymarket-copy
* pm2 stop polymarket-copy
* pm2 delete polymarket-copy
*/
const path = require('path');
const root = path.join(__dirname, '..');
module.exports = {
apps: [
{
name: 'polymarket-copy',
script: path.join(root, 'src/bot.js'),
interpreter: 'node',
// Live trading (default)
env: {
NODE_ENV: 'production',
DRY_RUN: 'false',
},
// Simulation: pm2 start pm2/copy.config.cjs --env sim
env_sim: {
NODE_ENV: 'production',
DRY_RUN: 'true',
},
out_file: path.join(root, 'logs/copy-out.log'),
error_file: path.join(root, 'logs/copy-error.log'),
log_date_format: 'YYYY-MM-DD HH:mm:ss Z',
merge_logs: true,
restart_delay: 5000,
max_restarts: 10,
min_uptime: '10s',
max_memory_restart: '256M',
stop_exit_codes: [0],
},
],
};
+47
View File
@@ -0,0 +1,47 @@
/**
* PM2 config — Market Maker Bot
*
* Usage (from project root):
* pm2 start pm2/mm.config.cjs # live trading
* pm2 start pm2/mm.config.cjs --env sim # simulation / dry-run
*
* pm2 logs polymarket-mm
* pm2 restart polymarket-mm
* pm2 stop polymarket-mm
* pm2 delete polymarket-mm
*/
const path = require('path');
const root = path.join(__dirname, '..');
module.exports = {
apps: [
{
name: 'polymarket-mm',
script: path.join(root, 'src/mm-bot.js'),
interpreter: 'node',
// Live trading (default)
env: {
NODE_ENV: 'production',
DRY_RUN: 'false',
},
// Simulation: pm2 start pm2/mm.config.cjs --env sim
env_sim: {
NODE_ENV: 'production',
DRY_RUN: 'true',
},
out_file: path.join(root, 'logs/mm-out.log'),
error_file: path.join(root, 'logs/mm-error.log'),
log_date_format: 'YYYY-MM-DD HH:mm:ss Z',
merge_logs: true,
restart_delay: 5000,
max_restarts: 10,
min_uptime: '10s',
max_memory_restart: '256M',
stop_exit_codes: [0],
},
],
};