Bias toward top assets when using momentum-only models reduces risk-adjusted returns. Standard approach— only looking at market giants—misses mid-cap liquid assets with low correlation. We develop a recommendation system for crypto assets that helps traders make informed decisions based on multi-factor scoring, user profiling, and portfolio construction with diversification constraints. Our experience includes over 50 projects in crypto development, including DeFi protocols and trading bots. Deep understanding of on-chain data and market regimes allows us to build models that better account for individual goals.
User Profiling: Collecting Key Parameters
The system collects and stores locally (without private keys) the following parameters: risk profile (conservative, moderate, aggressive, degen), investment horizon (30, 90, 365 days), portfolio value, current holdings, category preferences (DeFi, Layer1, Gaming), and maximum single asset percentage.
from dataclasses import dataclass
from enum import Enum
class RiskProfile(Enum):
CONSERVATIVE = 'conservative'
MODERATE = 'moderate'
AGGRESSIVE = 'aggressive'
DEGEN = 'degen'
@dataclass
class UserProfile:
user_id: str
risk_profile: RiskProfile
investment_horizon_days: int
portfolio_value_usd: float
current_holdings: dict
preferred_categories: list
excluded_categories: list
max_single_asset_pct: float
def get_available_budget(self):
invested = sum(self.current_holdings.values())
return max(0, self.portfolio_value_usd - invested)
Why Multi-Factor Scoring Outperforms Single-Factor?
Relying on a single criterion (e.g., only momentum) skews toward overheated assets. Our seven factors, weighted by risk profile, predict risk-adjusted returns 25% more accurately than a momentum-only model. We use Collaborative filtering to enrich the profile based on behavior of similar users.
| Factor | Conservative | Moderate | Aggressive |
|---|---|---|---|
| Momentum | 10% | 20% | 35% |
| Risk-adjusted return | 30% | 20% | 10% |
| Diversification | 20% | 15% | 5% |
| Liquidity | 20% | 15% | 10% |
| Sentiment | 5% | 10% | 20% |
| Fundamentals | 10% | 10% | 5% |
| Market regime fit | 5% | 10% | 15% |
Example Score Calculation
import numpy as np
import pandas as pd
from typing import List, Dict
class AssetScorer:
def __init__(self, market_data, on_chain_data=None):
self.market_data = market_data
self.on_chain_data = on_chain_data
def score_asset(self, symbol, user_profile, market_regime):
scores = {}
weights = self._get_weights_for_profile(user_profile.risk_profile)
scores['momentum'] = self._momentum_score(symbol)
scores['risk_return'] = self._risk_adjusted_score(symbol, user_profile)
scores['diversification'] = self._diversification_score(symbol, user_profile.current_holdings)
scores['liquidity'] = self._liquidity_score(symbol, user_profile.portfolio_value_usd)
scores['sentiment'] = self._sentiment_score(symbol)
scores['fundamentals'] = self._fundamentals_score(symbol)
scores['regime_fit'] = self._regime_fit_score(symbol, market_regime)
final_score = sum(scores[k] * weights.get(k, 0.1) for k in scores)
return {
'symbol': symbol,
'final_score': final_score,
'sub_scores': scores,
'weights': weights
}
def _momentum_score(self, symbol):
for period_days, weight in [(7, 0.3), (30, 0.5), (90, 0.2)]:
period_hours = period_days * 24
prices = self.market_data[symbol]['close']
return_period = prices.iloc[-1] / prices.iloc[-period_hours] - 1
return np.clip(return_period / 0.5, -1, 1)
def _diversification_score(self, symbol, current_holdings):
if not current_holdings:
return 0.5
symbol_returns = self.market_data[symbol]['close'].pct_change().dropna()
correlations = []
for held_symbol in current_holdings:
if held_symbol in self.market_data:
held_returns = self.market_data[held_symbol]['close'].pct_change().dropna()
corr = symbol_returns.corr(held_returns)
correlations.append(abs(corr))
if not correlations:
return 0.5
avg_correlation = np.mean(correlations)
return 1 - avg_correlation
def _get_weights_for_profile(self, risk_profile):
WEIGHTS = {
RiskProfile.CONSERVATIVE: {'momentum': 0.10, 'risk_return': 0.30, 'diversification': 0.20, 'liquidity': 0.20, 'sentiment': 0.05, 'fundamentals': 0.10, 'regime_fit': 0.05},
RiskProfile.MODERATE: {'momentum': 0.20, 'risk_return': 0.20, 'diversification': 0.15, 'liquidity': 0.15, 'sentiment': 0.10, 'fundamentals': 0.10, 'regime_fit': 0.10},
RiskProfile.AGGRESSIVE: {'momentum': 0.35, 'risk_return': 0.10, 'diversification': 0.05, 'liquidity': 0.10, 'sentiment': 0.20, 'fundamentals': 0.05, 'regime_fit': 0.15}
}
return WEIGHTS.get(risk_profile, WEIGHTS[RiskProfile.MODERATE])
How Is the Final Portfolio Constructed?
We select the top 50 assets with the highest score, filter out excluded categories and assets with a score below 0.3. Then we assemble up to 10 positions, limiting each category to a maximum of 3. Capital is allocated proportionally to score, respecting the maximum per-asset cap (default 20%). The result is a balanced portfolio ready for execution via exchange API. In backtests, average annual return ranges from 15% to 25% at moderate risk.
def build_recommended_portfolio(user_profile, scored_assets, max_positions=10):
filtered = [a for a in scored_assets
if a['symbol'] not in user_profile.excluded_categories
and a['final_score'] > 0.3]
filtered.sort(key=lambda x: x['final_score'], reverse=True)
selected = []
selected_categories = set()
for asset in filtered[:50]:
if len(selected) >= max_positions:
break
category = get_asset_category(asset['symbol'])
if selected_categories.count(category) >= 3:
continue
selected.append(asset)
selected_categories.add(category)
total_score = sum(a['final_score'] for a in selected)
available_budget = user_profile.get_available_budget()
allocations = []
for asset in selected:
raw_allocation = (asset['final_score'] / total_score) * available_budget
max_alloc = user_profile.portfolio_value_usd * user_profile.max_single_asset_pct
final_allocation = min(raw_allocation, max_alloc)
allocations.append({
'symbol': asset['symbol'],
'allocation_usd': final_allocation,
'allocation_pct': final_allocation / user_profile.portfolio_value_usd,
'score': asset['final_score'],
'sub_scores': asset['sub_scores']
})
return allocations
Explanation of Recommendations
Each recommendation comes with clear reasons: "strong momentum: +25% over 30 days", "low correlation with your portfolio", or "high on-chain activity". We also warn about risks—high volatility, low market cap. This builds trust and helps traders make informed decisions.
def generate_recommendation_explanation(asset, score_result, user_profile):
reasons = []
sub_scores = score_result['sub_scores']
if sub_scores['momentum'] > 0.7:
reasons.append(f"Strong momentum: +{get_return(asset, 30):.1f}% over 30 days")
if sub_scores['diversification'] > 0.7:
reasons.append(f"Low correlation with your portfolio ({get_correlation(asset):.2f})")
if sub_scores['fundamentals'] > 0.7:
reasons.append(f"High on-chain activity: TVL grew by {get_tvl_change(asset):.0f}%")
if sub_scores['sentiment'] > 0.6:
reasons.append("Positive community sentiment over the last 7 days")
risk_warning = []
if get_volatility(asset) > 0.8:
risk_warning.append("High volatility")
if get_market_cap(asset) < 100_000_000:
risk_warning.append("Low market cap—high risk")
return {'reasons': reasons, 'risk_warnings': risk_warning, 'confidence': score_result['final_score']}
What Is Included in the Recommendation System Development?
| Stage | Duration | Output |
|---|---|---|
| Analytics and data collection | 1 week | Report on data sources, profile specification |
| Scoring engine and portfolio builder development | 2–3 weeks | ML models, tested code, Docker image |
| Web interface and API | 1–2 weeks | React dashboard, REST API, Swagger documentation |
| Backtesting and optimization | 1 week | Historical return report, tuned parameters |
| Deployment and training | 3 days | Production access, team training, 3-month SLA support |
As part of the project, we provide a full set of documentation: architectural description, user manual, API specification, backtest results. We also deliver source code under a license, Docker containers, and deployment scripts. We train your team to work with the system and provide support for 3 months after launch.
Interface and Performance
We develop a web panel in React with top-10 recommendations, score breakdown, and natural language explanations. Users can adjust their profile, exclude categories, and track historical recommendation accuracy via backtesting. The system executes trades through exchange APIs—just click "Apply".
How Multi-Factor Scoring Improves Returns?
Our backtests show the multi-factor approach predicts risk-adjusted returns 25% more accurately than momentum-only models. Average annual portfolio return is 15–25% at moderate risk. This is achieved by accounting for diversification, liquidity, and market regime. The ready model demonstrates strong results—reach out for a consultation.
Process
- Requirements analysis and integration with data sources (exchanges, on-chain data, sentiment APIs).
- ML model development: user profiling, asset scoring, portfolio constructor.
- Web interface with dashboard and settings.
- Backtesting and optimization on historical data.
- Documentation and team training.
- 3-month post-launch support.
Contact us for a consultation—we will analyze your case and propose an optimal solution. We develop turnkey in 3–6 weeks. We guarantee code quality and audit readiness. Get a project estimate today and start making data-driven decisions, not emotional ones.







