Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 51 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
### Smart Money Follower

Smart Money Follower OG Developer: https://github.com/yllvar <br>
OG Repo: https://github.com/yllvar/Smart_Money_Follower <br><br>
GMGN.ai API Wrapper OG Developer: https://github.com/1f1n <br>
OG Repo: https://github.com/1f1n/gmgnai-wrapper

#### Overview
The **Smart Money Follower** is a Python-based tool designed to analyze and follow top-performing wallets in the cryptocurrency space using the GMGN.ai API. It provides insights into wallet activities, evaluates traded tokens, and presents data in a structured format for analysis.

Expand All @@ -12,24 +17,60 @@ The **Smart Money Follower** is a Python-based tool designed to analyze and foll
#### Requirements
- Python 3.7+
- Dependencies:
- `httpx`
- `fake-useragent`
- `tabulate`
- `gmgn` (GMGN.ai API wrapper)
- `logging`
- `tls_client`
- `PyYAML`

#### Setup
1. **Installation**:
```bash
pip install httpx tabulate gmgn
## Setup
#### 1. **Clone Git**

```
git clone https://github.com/LetsStartWithPurple/Smart_Money_Follower.git
```
#### 2. **Start Virtual Environment**

2. **Configuration**:
- Ensure you have valid API credentials for GMGN.ai. Update credentials in the `gmgn` initialization within `SmartMoneyFollower`.
Navigate to the project directory:
```bash
cd Smart_Money_Follower
```
Create Venv
```bash
python3 -m venv venv
```
Start Virtual Environment
```bash
source venv/bin/activate
```

3. **Execution**:
#### 4. **Install Requirements**:
```bash
pip install -r requirements.txt
```

#### 5. **Execution**:
```bash
python smart_money_follower.py
```
```bash
usage: smart_money_follower.py [-h] [--config CONFIG] [--path PATH] [--verbose VERBOSE]
[--export-format {csv,txt}] [--timeframe {1d,7d,30d}]
[--winrate WINRATE]

Smart Money Follower Configuration

options:
-h, --help show this help message and exit
--config CONFIG Path to the config file
--path PATH Path to export files
--verbose VERBOSE Verbose script logs
--export-format {csv,txt}
Export format (csv or txt)
--timeframe {1d,7d,30d}
Select timeframe of wallet scan
--winrate WINRATE Set winrate between 0 and 100
```
or you can adjust these settings in the config/config.yaml file

#### Usage
- Upon execution, the script fetches top wallets, analyzes their recent activities, evaluates tokens they've traded, and prints out a summarized analysis including realized profits, transaction volumes, and last activity timestamps.
Expand Down
131 changes: 131 additions & 0 deletions config/ConfigManager.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
import argparse
import yaml
import os
from yaml import YAMLError
from config.config_validators import *


class ConfigManager:
def __init__(self, args=None):
self._config_path = os.path.abspath(args.config)
self._config_data = self._load_config()
self._args = args
self._final_config = self._merge_config_and_args()

def _load_config(self):
"""Load the configuration file."""
try:
with open(self._config_path, 'r') as f:
return yaml.safe_load(f)
except FileNotFoundError:
print(f"Warning: Config file '{self._config_path}' not found. Using defaults.")
return {}
except YAMLError as e:
print(f"Error: Failed to parse YAML in config file '{self._config_path}': {e}")
return {}

def _merge_config_and_args(self):
"""Merge the config file and command-line arguments, with args taking precedence."""
wallet_settings = self._config_data.get("wallet_settings", {})
return {
"path": validate_path(
self._args.path if self._args and self._args.path else self._config_data.get("path", "data")
),
"verbose": validate_verbose(
self._args.verbose if self._args and self._args.verbose else self._config_data.get("verbose", True)
),
"export_format": validate_export_format(
self._args.export_format if self._args and self._args.export_format else self._config_data.get("export_format", "csv")
),
"timeframe": validate_timeframe(
self._args.timeframe if self._args and self._args.timeframe else wallet_settings.get("timeframe", "7d")
),
"wallet_tag": validate_wallet_tag(
wallet_settings.get("wallet_tag", "smart_degen")
),
"win_rate": validate_win_rate(
self._args.winrate if self._args and self._args.winrate else wallet_settings.get("win_rate", 60)
)
}

@property
def path(self):
return self._final_config["path"]

@path.setter
def path(self, new_path):
self._final_config["path"] = validate_path(new_path)

@property
def verbose(self):
return self._final_config["verbose"]

@verbose.setter
def verbose(self, verbose):
self._final_config["verbose"] = validate_verbose(verbose)

@property
def export_format(self):
return self._final_config["export_format"]

@export_format.setter
def export_format(self, export_format):
self._final_config["export_format"] = validate_export_format(export_format)

@property
def timeframe(self):
return self._final_config["timeframe"]

@timeframe.setter
def timeframe(self, timeframe):
self._final_config["timeframe"] = validate_timeframe(timeframe)

@property
def wallet_tag(self):
return self._final_config["wallet_tag"]

@wallet_tag.setter
def wallet_tag(self, wallet_tag):
self._final_config["wallet_tag"] = validate_wallet_tag(wallet_tag)

@property
def win_rate(self):
return self._final_config["win_rate"]

@win_rate.setter
def win_rate(self, win_rate):
self._final_config["win_rate"] = validate_win_rate(win_rate)

@property
def config(self):
return self._final_config


def parse_args():
"""Parse command-line arguments."""
parser = argparse.ArgumentParser(description="Smart Money Follower Configuration")
parser.add_argument("--config", type=str, default="config/config.yaml", help="Path to the config file")
parser.add_argument("--path", type=str, help="Path to export files")
parser.add_argument("--verbose", type=bool, help="Verbose script logs")
parser.add_argument("--export-format", type=str, choices=["csv", "txt"], help="Export format (csv or txt)")
parser.add_argument("--timeframe", type=str, choices=["1d", "7d", "30d"], help="Select timeframe of wallet scan")
parser.add_argument("--winrate", type=int, help="Set winrate between 0 and 100")
return parser.parse_args()


if __name__ == "__main__":
# Parse arguments
args = parse_args()
#args.config = "config.yaml" # for testing purposes

# Create ConfigManager instance
config_manager = ConfigManager(args=args)

# Access properties
print("Final Configuration:")
print(f"Path: {config_manager.path}")
print(f"Verbose: {config_manager.verbose}")
print(f"Export Format: {config_manager.export_format}")
print(f"Timeframe: {config_manager.timeframe}")
print(f"Wallet Tag: {config_manager.wallet_tag}")
print(f"Win Rate: {config_manager.win_rate}")
Empty file added config/__init__.py
Empty file.
26 changes: 26 additions & 0 deletions config/config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#### Path to export wallet data
path: "data"

#### Export settings
# csv or txt
export_format: "csv"

#### Verbose Settings
verbose: False

#### Wallet Search settings
# timeframe options - 1d, 7d, 30d
#
# wallet tags options -
# all = all tags
# pump_smart = Pump.Fun Smart Money
# smart_degen = Smart Money (default)
# reowned = KOL/VC/Influencer
# snipe_bot = Snipe Bot
#
# winrate - set 0 to 100 (default is 60)

wallet_settings:
timeframe: "7d"
wallet_tag: "smart_degen"
win_rate: 60
34 changes: 34 additions & 0 deletions config/config_validators.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
def validate_path(path):
if not isinstance(path, str):
raise ValueError("Path must be a string")
return path

def validate_verbose(verbose):
if not isinstance(verbose, bool):
raise ValueError("Verbose must be a boolean")
return verbose

def validate_export_format(export_format):
valid_formats = ["csv", "txt"]
if export_format not in valid_formats:
raise ValueError("Export format must be 'csv' or 'txt'")
return export_format

def validate_timeframe(timeframe):
valid_timeframes = ["1d", "7d", "30d"]
if timeframe not in valid_timeframes:
raise ValueError("Timeframe must be '1d', '7d', or '30d'.")
return timeframe

def validate_wallet_tag(wallet_tag):
valid_tags = ["all", "pump_smart", "smart_degen", "reowned", "snipe_bot"]
if wallet_tag not in valid_tags:
raise ValueError(f"Wallet tag must be one of {valid_tags}")
return wallet_tag

def validate_win_rate(win_rate):
if not isinstance(win_rate, int):
raise ValueError("Win Rate must be an integer")
elif not (0 <= win_rate <= 100):
raise ValueError("Win Rate must be between 0 and 100")
return win_rate / 100
Empty file added gmgn/__init__.py
Empty file.
Loading