Tokenlysis is a cryptocurrency scoring platform. The current proof of concept fetches a configurable top N
assets (50 by default) from CoinGecko, computes Liquidity and Opportunity scores and aggregates them into a global score refreshed daily.
The long‑term goal is to rank more than 1,000 crypto-assets and highlight 100 trending tokens outside the top market-cap list. Additional categories and features will arrive in the MVP phase.
For a full overview of features and architecture, see the functional specifications.
- Universe: configurable top
N
assets (default 50) from CoinGecko (MVP: top 1000 + 100 trending). - Update schedule: data is refreshed every 12 hours.
- Startup: fetch live data when the database isn't bootstrapped, otherwise load the bundled seed.
- Scores: Liquidity, Opportunity and Global (MVP: six categories: Community, Liquidity, Opportunity, Security, Technology, Tokenomics).
Feature | Implemented | Planned |
---|---|---|
Configurable top N (default 50) | ✅ | Top 1000 + 100 trending |
Liquidity & Opportunity scores + Global | ✅ | Six categories with custom weights |
Refresh every 12 hours | ✅ | DB + daily snapshots |
Static frontend table | ✅ | Rich charts & filtering |
/version endpoint |
✅ | Auth & watchlists |
Seed fallback controlled by USE_SEED_ON_FAILURE |
✅ | Quotas & rate limiting |
- Metrics: 24h trading volume (45%), market capitalization (35%), exchange listings (20%).
- Method: logarithmic scaling and percentile normalization.
- Metrics: 14‑day RSI (60%) and day‑over‑day volume change (40%).
- Method: RSI inverted above 70 to reward oversold assets; volume change normalized on a 0‑100 scale.
- Metrics: Twitter followers (50%), 30‑day follower growth (30%), combined Discord/Reddit activity (20%).
- Metrics: number of completed audits (50%), network decentralization (30%), days since last major incident (20%).
- Metrics: commits over the last 3 months (60%), active contributors (40%).
- Metrics: supply distribution (40%), inflation rate (30%), vesting/unlock schedule (30%).
- Liquidity scoring
- Opportunity scoring
- Global score aggregation
- Mock ETL generating sample data
- REST API for
/ranking
,/asset/{id}
and/history/{id}
- Static frontend table served by the backend
- Docker Compose setup for backend and frontend (deployable on Synology NAS)
- Community scoring
- Security scoring
- Technology scoring
- Tokenomics scoring
- Trending asset detection
- Persistent PostgreSQL storage
- User-defined weighting UI
- Interactive charts and comparisons
- User accounts, authentication and watchlists
- Worker queue, caching layer and API rate limiting
- Historical score charts with price overlays and CSV export
- CI/CD pipeline with staging environment
- 80 %+ test coverage and load testing
- ETL – Python scripts pull data from external APIs and compute daily metrics and scores.
- API – A FastAPI application serves the scores and historical series.
- Frontend – A minimal HTML/JS client displays a table of assets. Future versions will add filtering and charts.
- Python 3.11+
- Install dependencies:
pip install -r backend/requirements.txt
uvicorn backend.app.main:app --reload
The frontend is served statically by the API under /
while the REST endpoints
are exposed under /api
.
Set APP_VERSION
when launching locally so the interface displays the
expected version:
APP_VERSION=1.2.3 uvicorn backend.app.main:app --reload
Copy .env.example
to .env
and adjust the values as needed. This file holds sensitive settings such as API keys and database passwords. Keep it outside version control (it is ignored by .gitignore
) and restrict access on your NAS, for example with chmod 600 .env
.
Runtime behaviour can be tweaked with environment variables:
CORS_ORIGINS
– comma-separated list of allowed origins (default:http://localhost
)CG_TOP_N
– number of assets fetched from CoinGecko (default:20
)CG_DAYS
– number of days of history to retrieve (default:14
)CG_MONTHLY_QUOTA
– maximum CoinGecko API calls per month (default:10000
)CG_PER_PAGE_MAX
– preferred page size for/coins/markets
calls (default:250
)CG_ALERT_THRESHOLD
– fraction of the monthly quota that triggers a scope reduction (default:0.7
)REFRESH_GRANULARITY
– cron-like hint exposed by/api/diag
(default:12h
). Changing this value updates the ETL scheduler without restarting the app.COINGECKO_BASE_URL
– override for the CoinGecko API endpoint (defaults to the public URL or Pro URL based onCOINGECKO_PLAN
)COINGECKO_API_KEY
– optional API key for CoinGeckoCOINGECKO_PLAN
–demo
(default) orpro
to select the API headerCG_THROTTLE_MS
– minimum delay in milliseconds between CoinGecko API callsBUDGET_FILE
– path to the persisted CoinGecko call budget JSON fileDATABASE_URL
– SQLAlchemy database URLUSE_SEED_ON_FAILURE
– fall back to bundled seed data when live ETL fails (default:true
)SEED_FILE
– path to the seed data used whenUSE_SEED_ON_FAILURE
is enabled (default:./backend/app/seed/top20.json
)LOG_LEVEL
– base logging level for application and Uvicorn loggers (default:INFO
). Accepts an integer or one ofDEBUG
,INFO
,WARN
,WARNING
,ERROR
,CRITICAL
,FATAL
orNOTSET
. Unknown values fall back toINFO
with a warning. UseUVICORN_LOG_LEVEL
or--log-level
to override server log level separately. CoinGecko client and the ETL emit one-line JSON logs with endpoint and latency fields.
When deploying on a Synology NAS, mount persistent volumes so the database and budget survive container restarts:
/volume1/docker/tokenlysis/data ↔ /data
The .env.example
illustrates the host paths to persist data:
DATABASE_URL=sqlite:////volume1/docker/tokenlysis/data/tokenlysis.db
BUDGET_FILE=/volume1/docker/tokenlysis/data/budget.json
These map inside the container to/data
. Ensure the container user has write permissions on the host directories.
Do not define environment variables with empty values. If a value is not
needed, remove the variable or comment it out in .env
. On Synology, delete the
variable from the UI instead of leaving the field blank. Quotes around values
(e.g. LOG_LEVEL="INFO"
) are ignored.
Boolean variables accept true/false/1/0/yes/no/on/off
(case-insensitive, surrounding
whitespace allowed). Empty or unrecognised values fall back to their defaults.
Integer variables behave similarly: empty strings use the default and invalid numbers
raise an explicit error.
The ETL fetches market data using CoinGecko's coin IDs. During development the
seed assets (C1
, C2
, …) are mapped to real CoinGecko IDs through
backend/app/config/seed_mapping.py
.
GET /healthz
– returns DB connectivity, bootstrap status and last refresh timeGET /readyz
– readiness check for the web process ({"ready": true}
)GET /api/markets/basic
– minimal market data fallbackGET /api/diag
– debug info: plan, granularity, last refresh, ETL rows, call budgetGET /version
– application version ({"version": "<hash>"}
)
GET /api/markets/top
– top assets (limit
clamped to[1, CG_TOP_N]
,vs
must beusd
), returns{ "items": [...], "last_refresh_at": "...", "stale": bool, "data_source": "api|seed" }
The following steps describe how to deploy Tokenlysis on a Synology NAS using the local source code.
-
Install Container Manager – from the Synology Package Center install the Container Manager application (formerly called Docker).
-
Clone the project – obtain the Tokenlysis repository on your NAS, e.g.:
git clone https://github.com/Tomp0uce/Tokenlysis.git cd Tokenlysis
Create a
.env
file from the example and secure it on the NAS:cp .env.example .env chmod 600 .env
-
Create the project – in Container Manager, go to Project → Create and select the
docker-compose.yml
file from the cloned folder. Adddocker-compose.synology.yml
as an additional compose file so the image is built locally. When defining environment variables in the Synology UI, never leave a value empty. If you don't have a value, remove the variable instead of leaving it blank. Supported boolean values aretrue
,false
,1
,0
,yes
,no
,on
andoff
(case-insensitive); an empty value is treated as unset and defaults are applied. -
Build and start – from the NAS terminal run:
APP_VERSION=1.0.123 \ docker compose -f docker-compose.yml -f docker-compose.synology.yml build --no-cache docker compose -f docker-compose.yml -f docker-compose.synology.yml up -d
The build step injects the desired version into the image (defaults to
dev
). The subsequentup
starts the container. A healthcheck inside the container pollshttp://localhost:8000/readyz
every 30 seconds. -
Access the app – once running the interface is available at
http://<NAS_IP>:8002
.
To update with a pinned version:
APP_VERSION=1.0.123 \
docker compose -f docker-compose.yml -f docker-compose.synology.yml build --no-cache
docker compose -f docker-compose.yml -f docker-compose.synology.yml up -d
pytest
Docker images embed a version string that defaults to the number of commits in
the repository. The value is passed at build time through the APP_VERSION
build argument and is exposed inside the container as the APP_VERSION
environment variable. The same value is also written to the
org.opencontainers.image.version
OCI label for traceability.
GitHub Actions sets the value to 1.0.<run_number>
using github.run_number
and
injects it with --build-arg APP_VERSION=${APP_VERSION}
during the build. When
building locally you can override the version:
docker build --build-arg APP_VERSION=42 -t tokenlysis:test -f ./Dockerfile .
To propagate a new version to the dashboard and API, the image must be rebuilt with the desired value:
APP_VERSION=1.2.3 \
docker compose -f docker-compose.yml -f docker-compose.synology.yml build --no-cache
docker compose -f docker-compose.yml -f docker-compose.synology.yml up -d
At runtime the container exposes APP_VERSION
so it can be inspected with
docker run --rm tokenlysis:test env | grep APP_VERSION
.
During the build the same value is also written to frontend/app-version.js
so the static dashboard can display the version even if the API is
unreachable.
This project is licensed under the MIT License.