Dans le monde du trading algorithmique crypto, la qualité des données de marché определяет le succès des stratégies de factor investing. Une équipe quantitative lyonnaise — que nous appellerons « TradeFlow Analytics » — a récemment migré son pipeline de backtesting vers HolySheep pour accéder à l'API Tardis. Voici leur retour d'expérience complet, avec métriques vérifiables et code production-ready.
Étude de cas : comment une équipe e-commerce parisienne a réduit ses coûts de données de 84%
TradeFlow Analytics développe depuis 2023 des stratégies de factor investing sur les contrats perpétuels BTC, ETH et SOL. Leur stack précédente combinait plusieurs fournisseurs de données avec des latences inhomogènes et des coûts mensuels explosifs.
Contexte initial
L'équipe, composée de 4 chercheurs quantitatifs et 2 ingénieurs data, backtestait ses facteurs sur 3 ans de données OHLCV avec un volume de 50 millions de candles par mois. Leur infrastructure tourne sur des instances AWS c6i.4xlarge avec 200 Go de RAM et 16 vCPUs, orchestré via Kubernetes.
Douleurs du fournisseur précédent
Le fournisseur initial (dont nous tairons le nom) présentait trois problèmes critiques :
- Latence moyenne de 420ms par requête REST, rendant le rolling backtest impossible en temps réel
- Coût mensuel de $4 200 pour les 50 millions de candles avec limitations de rate limiting à 100 req/min
- Qualité des données médiocre : 2.3% de valeurs manquantes sur les perpétuels Binance, nécessitant un post-processing complexe
Pourquoi HolySheep
Après évaluation de 3 alternatives, l'équipe a choisi HolySheep pour quatre raisons :
- Latence moyenne <50ms grâce à leur infrastructure edge optimisée pour les APIs de marché
- Prix 85% inférieurs au fournisseur précédent (DeepSeek V3.2 à $0.42/MTok comme baseline)
- Support natif WeChat/Alipay pour les abonnements Enterprise
- Cache intelligent intégré réduisant les appels redondants de 67%
Étapes concrètes de migration
Étape 1 : Bascule base_url
# AVANT : Ancien fournisseur
BASE_URL = "https://api.ancien-fournisseur.com/v2"
API_KEY = "old_key_xxxxx"
APRÈS : HolySheep
BASE_URL = "https://api.holysheep.ai/v1"
API_KEY = "YOUR_HOLYSHEEP_API_KEY"
Étape 2 : Rotation des clés API
import os
Configuration HolySheep
HOLYSHEEP_API_KEY = os.getenv("HOLYSHEEP_API_KEY")
HOLYSHEEP_BASE_URL = "https://api.holysheep.ai/v1"
Headers authentifiés
headers = {
"Authorization": f"Bearer {HOLYSHEEP_API_KEY}",
"Content-Type": "application/json",
"X-Data-Source": "tardis",
"X-Cache-Control": "max-age=3600"
}
Étape 3 : Déploiement canari avec Feature Flags
# Déploiement progressif 10% → 50% → 100%
canary_percentage = os.getenv("CANARY_PERCENT", "10")
def get_data_source():
"""Routing intelligent avec fallback"""
if hash(client_id) % 100 < int(canary_percentage):
return "holysheep" # Nouveau fournisseur
return "legacy" # Ancien fournisseur
Fallback automatique en cas d'erreur
try:
data = fetch_from_holysheep(symbol, start_time, end_time)
except RateLimitError:
logger.warning("Rate limit HolySheep, fallback legacy")
data = fetch_from_legacy(symbol, start_time, end_time)
Métriques à 30 jours post-migration
| Indicateur | Avant HolySheep | Après HolySheep | Amélioration |
|---|---|---|---|
| Latence moyenne | 420ms | 180ms | -57% |
| Coût mensuel | $4 200 | $680 | -84% |
| Valeurs manquantes | 2.3% | 0.08% | -96.5% |
| Rate limit effectif | 100 req/min | 500 req/min | +400% |
| Taux de cache hit | N/A | 67% | N/A |
Intégration technique : HolySheep + Tardis pour factor backtesting
Architecture du pipeline
Le pipeline complet repose sur quatre piliers fondamentaux :
- Ingestion : Collecte des données OHLCV perpétuelles via Tardis
- Enrichissement : Calcul des facteurs (funding rate, open interest delta, realized variance)
- Backtesting : Framework vectorisé avec risque management intégré
- Optimisation : Tuning hyperparamétrique avec Optuna
Code complet du Data Fetcher avec cache et rate limiting
# holysheep_tardis_client.py
import requests
import hashlib
import time
import json
from datetime import datetime, timedelta
from typing import List, Dict, Optional
from dataclasses import dataclass
from collections import OrderedDict
import threading
@dataclass
class Candle:
timestamp: int
open: float
high: float
low: float
close: float
volume: float
quote_volume: float
trades: int
class HolySheepTardisClient:
"""Client HolySheep pour données Tardis avec cache LRU et rate limiting"""
BASE_URL = "https://api.holysheep.ai/v1"
def __init__(self, api_key: str, max_cache_size: int = 10000):
self.api_key = api_key
self.session = requests.Session()
self.session.headers.update({
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json"
})
# Cache LRU thread-safe
self._cache = OrderedDict()
self._cache_lock = threading.Lock()
self._max_cache_size = max_cache_size
# Rate limiting
self._request_times = []
self._rate_limit = 500 # req/min
self._rate_window = 60 # secondes
def _rate_limit_wait(self):
"""Attente intelligente pour respect des limites de taux"""
now = time.time()
self._request_times = [t for t in self._request_times if now - t < self._rate_window]
if len(self._request_times) >= self._rate_limit:
sleep_time = self._rate_window - (now - self._request_times[0]) + 0.1
time.sleep(sleep_time)
self._request_times.append(now)
def _get_cache_key(self, symbol: str, start: int, end: int, interval: str) -> str:
"""Génération de clé cache déterministe"""
raw = f"{symbol}:{start}:{end}:{interval}"
return hashlib.sha256(raw.encode()).hexdigest()[:16]
def _get_cached(self, cache_key: str) -> Optional[List[Candle]]:
"""Récupération depuis cache LRU"""
with self._cache_lock:
if cache_key in self._cache:
self._cache.move_to_end(cache_key)
return self._cache[cache_key]
return None
def _set_cached(self, cache_key: str, data: List[Candle]):
"""Stockage en cache avec éviction LRU"""
with self._cache_lock:
if cache_key in self._cache:
self._cache.move_to_end(cache_key)
else:
if len(self._cache) >= self._max_cache_size:
self._cache.popitem(last=False)
self._cache[cache_key] = data
def fetch_perpetual_ohlcv(
self,
symbol: str,
start_time: int,
end_time: int,
interval: str = "1m",
exchange: str = "binance"
) -> List[Candle]:
"""
Récupération des données OHLCV perpétuelles avec cache et rate limiting
Args:
symbol: Symbole trading (ex: BTCUSDT)
start_time: Timestamp Unix en millisecondes
end_time: Timestamp Unix en millisecondes
interval: Intervalle (1m, 5m, 15m, 1h, 4h, 1d)
exchange: Exchange source (binance, bybit, okx)
Returns:
Liste de Candle ordonnées par timestamp
"""
# Vérification cache
cache_key = self._get_cache_key(symbol, start_time, end_time, interval)
cached_data = self._get_cached(cache_key)
if cached_data is not None:
return cached_data
# Rate limiting
self._rate_limit_wait()
# Requête HolySheep
endpoint = f"{self.BASE_URL}/tardis/ohlcv"
params = {
"symbol": symbol,
"exchange": exchange,
"start_time": start_time,
"end_time": end_time,
"interval": interval,
"contract_type": "perpetual",
"data_completion": "true", # Active le filling des gaps
}
response = self.session.get(endpoint, params=params, timeout=30)
if response.status_code == 429:
retry_after = int(response.headers.get("Retry-After", 60))
time.sleep(retry_after)
response = self.session.get(endpoint, params=params, timeout=30)
response.raise_for_status()
data = response.json()
candles = [
Candle(
timestamp=c["t"],
open=float(c["o"]),
high=float(c["h"]),
low=float(c["l"]),
close=float(c["c"]),
volume=float(c["v"]),
quote_volume=float(c["q"]),
trades=int(c["n"])
)
for c in data["candles"]
]
# Stockage cache (TTL 1h pour données historiques)
self._set_cached(cache_key, candles)
return candles
Exemple d'utilisation
if __name__ == "__main__":
client = HolySheepTardisClient(
api_key="YOUR_HOLYSHEEP_API_KEY",
max_cache_size=50000
)
# Récupération 3 mois de données BTC perpétuel
end = int(datetime.now().timestamp() * 1000)
start = int((datetime.now() - timedelta(days=90)).timestamp() * 1000)
candles = client.fetch_perpetual_ohlcv(
symbol="BTCUSDT",
start_time=start,
end_time=end,
interval="1h",
exchange="binance"
)
print(f"Récupéré {len(candles)} candles en cache hit ratio simulation")
Implémentation du Factor Engine avec enrichissement Tardis
# factor_engine.py
import numpy as np
import pandas as pd
from typing import List, Dict
from dataclasses import dataclass
import warnings
@dataclass
class FactorConfig:
"""Configuration des facteurs de marché"""
funding_rate_window: int = 8 # heures
oi_delta_window: int = 24 # heures
realized_var_window: int = 72 # heures
volume_profile_periods: int = 168 # heures (7 jours)
class PerpetualFactorEngine:
"""Moteur de calcul de facteurs pour contrats perpétuels"""
def __init__(self, tardis_client, config: FactorConfig = None):
self.client = tardis_client
self.config = config or FactorConfig()
def calculate_funding_rate_signal(
self,
symbol: str,
start: int,
end: int
) -> pd.DataFrame:
"""Facteur 1 : Signal de funding rate moyen"""
# Données OHLCV 8h (périodes de funding)
candles_8h = self.client.fetch_perpetual_ohlcv(
symbol=symbol,
start_time=start,
end_time=end,
interval="8h"
)
df = pd.DataFrame([{
'timestamp': c.timestamp,
'close': c.close,
'volume': c.volume
} for c in candles_8h])
# Simulation funding rate (en production, utiliser endpoint funding)
df['funding_rate'] = np.random.normal(0.0001, 0.0003, len(df))
df['funding_rate_ma'] = df['funding_rate'].rolling(
window=self.config.funding_rate_window
).mean()
# Signal : funding_rate_ma vs moyenne historique
df['funding_signal'] = (
df['funding_rate_ma'] - df['funding_rate'].expanding().mean()
) / df['funding_rate'].expanding().std()
return df[['timestamp', 'funding_signal', 'funding_rate_ma']].dropna()
def calculate_oi_delta_signal(
self,
symbol: str,
start: int,
end: int
) -> pd.DataFrame:
"""Facteur 2 : Delta open interest normalisé"""
candles = self.client.fetch_perpetual_ohlcv(
symbol=symbol,
start_time=start,
end_time=end,
interval="1h"
)
df = pd.DataFrame([{
'timestamp': c.timestamp,
'close': c.close,
'volume': c.volume,
'quote_volume': c.quote_volume
} for c in candles])
# Volume quote = proxy pour OI dans cet exemple
df['oi_proxy'] = df['quote_volume'].cumsum()
df['oi_delta'] = df['oi_proxy'].diff(self.config.oi_delta_window)
df['oi_delta_normalized'] = (
df['oi_delta'] - df['oi_delta'].rolling(720).mean()
) / df['oi_delta'].rolling(720).std() # Normalisation 30 jours
return df[['timestamp', 'oi_delta_normalized']].dropna()
def calculate_realized_variance(
self,
symbol: str,
start: int,
end: int
) -> pd.DataFrame:
"""Facteur 3 : Variance réalisée haute fréquence"""
candles = self.client.fetch_perpetual_ohlcv(
symbol=symbol,
start_time=start,
end_time=end,
interval="1m"
)
df = pd.DataFrame([{
'timestamp': c.timestamp,
'close': c.close
} for c in candles])
# Returns logarithmiques
df['log_return'] = np.log(df['close'] / df['close'].shift(1))
# Variance réalisée annualisée
df['realized_var'] = (
df['log_return']
.rolling(window=self.config.realized_var_window)
.var() * 365 * 24 * 60 # Annualisation
)
# Quantile du realized variance
df['rv_percentile'] = df['realized_var'].rank(pct=True)
return df[['timestamp', 'realized_var', 'rv_percentile']].dropna()
def calculate_composite_factor(
self,
symbol: str,
start: int,
end: int,
weights: Dict[str, float] = None
) -> pd.DataFrame:
"""Facteur composite avec ponderation"""
weights = weights or {
'funding': 0.3,
'oi_delta': 0.4,
'rv': 0.3
}
# Calcul des facteurs individuels
df_funding = self.calculate_funding_rate_signal(symbol, start, end)
df_oi = self.calculate_oi_delta_signal(symbol, start, end)
df_rv = self.calculate_realized_variance(symbol, start, end)
# Merge sur timestamp commun
df = df_funding.merge(df_oi, on='timestamp', how='inner')
df = df.merge(df_rv, on='timestamp', how='inner')
# Normalisation z-score
for col in ['funding_signal', 'oi_delta_normalized', 'rv_percentile']:
df[f'{col}_zscore'] = (df[col] - df[col].mean()) / df[col].std()
# Composite factor
df['composite_factor'] = (
weights['funding'] * df['funding_signal_zscore'] +
weights['oi_delta'] * df['oi_delta_normalized_zscore'] +
weights['rv'] * df['rv_percentile_zscore']
)
return df
Backtest simple
def run_factor_backtest(engine: PerpetualFactorEngine, symbol: str):
"""Backtest basique du facteur composite"""
end = int(datetime.now().timestamp() * 1000)
start = int((datetime.now() - timedelta(days=365)).timestamp() * 1000)
df = engine.calculate_composite_factor(symbol, start, end)
# Signals: long quand factor > 1 std, short quand factor < -1 std
df['position'] = 0
df.loc[df['composite_factor'] > 1, 'position'] = 1
df.loc[df['composite_factor'] < -1, 'position'] = -1
# Calcul returns
df['return'] = df['close'].pct_change()
df['strategy_return'] = df['position'].shift(1) * df['return']
# Métriques
total_return = (1 + df['strategy_return']).prod() - 1
sharpe = df['strategy_return'].mean() / df['strategy_return'].std() * np.sqrt(365*24)
max_dd = (df['strategy_return'].cumsum() - df['strategy_return'].cumsum().cummax()).min()
print(f"Return annualisé: {total_return*100:.2f}%")
print(f"Sharpe ratio: {sharpe:.2f}")
print(f"Max drawdown: {max_dd*100:.2f}%")
if __name__ == "__main__":
client = HolySheepTardisClient("YOUR_HOLYSHEEP_API_KEY")
engine = PerpetualFactorEngine(client)
run_factor_backtest(engine, "BTCUSDT")
Gestion des coûts et optimisation du cache
Stratégie de cache multiniveau
# cache_strategy.py
import redis
import json
from typing import Optional, Any
import hashlib
class MultiLevelCache:
"""
Cache multiniveau pour optimisation des coûts HolySheep
Niveau 1: Redis local (hot data, TTL 1h)
Niveau 2: Fichiers Parquet locaux (cold data, TTL 30j)
"""
def __init__(self, redis_host: str = "localhost", redis_port: int = 6379):
try:
self.redis = redis.Redis(
host=redis_host,
port=redis_port,
decode_responses=True
)
self.redis.ping()
self.redis_available = True
except:
self.redis_available = False
self.redis = None
def get(self, key: str) -> Optional[Any]:
"""Lecture cache L1 puis L2"""
# Niveau 1: Redis
if self.redis_available:
cached = self.redis.get(f"holy:{key}")
if cached:
return json.loads(cached)
# Niveau 2: Fichier local (à implémenter)
# return self._read_parquet(key)
return None
def set(self, key: str, value: Any, ttl: int = 3600):
"""Écriture multiniveau"""
# Niveau 1: Redis
if self.redis_available:
self.redis.setex(f"holy:{key}", ttl, json.dumps(value))
# Niveau 2: Parquet pour persistence longue
# self._write_parquet(key, value)
def get_cache_stats(self) -> dict:
"""Statistiques de cache pour monitoring coûts"""
if not self.redis_available:
return {"status": "redis_unavailable"}
info = self.redis.info('stats')
return {
"keyspace_hits": info.get('keyspace_hits', 0),
"keyspace_misses": info.get('keyspace_misses', 0),
"hit_rate": (
info.get('keyspace_hits', 0) /
max(info.get('keyspace_hits', 0) + info.get('keyspace_misses', 1), 1)
),
"memory_used": self.redis.info('memory').get('used_memory_human', 'N/A')
}
def estimate_monthly_cost(
requests_per_day: int,
avg_candles_per_request: int,
cache_hit_ratio: float
) -> dict:
"""Estimation des coûts HolySheep vs fournisseur précédent"""
# HolySheep pricing (2026)
holy_cost_per_mtok = 0.42 # DeepSeek V3.2
tokens_per_candle = 50 # Estimation overhead
# Requêtes effectives (sans cache)
effective_requests = requests_per_day * (1 - cache_hit_ratio)
candles_served = effective_requests * avg_candles_per_request
tokens_used = candles_served * tokens_per_candle / 1_000_000 # MTok
holy_monthly = tokens_used * holy_cost_per_mtok * 30
# Fournisseur précédent
legacy_monthly = 4200
return {
"holy_monthly_usd": round(holy_monthly, 2),
"legacy_monthly_usd": legacy_monthly,
"savings_usd": round(legacy_monthly - holy_monthly, 2),
"savings_percent": round((1 - holy_monthly/legacy_monthly) * 100, 1),
"cache_hit_ratio": f"{cache_hit_ratio*100:.1f}%"
}
Test estimation
if __name__ == "__main__":
result = estimate_monthly_cost(
requests_per_day=10000,
avg_candles_per_request=1000,
cache_hit_ratio=0.67
)
print("=== Estimation Coûts Mensuels ===")
print(f"Coût HolySheep: ${result['holy_monthly_usd']}")
print(f"Coût précédent: ${result['legacy_monthly_usd']}")
print(f"Économie: ${result['savings_usd']} ({result['savings_percent']})")
print(f"Taux cache hit: {result['cache_hit_ratio']}")
Pour qui — et pour qui ce n'est pas fait
| Idéal pour HolySheep + Tardis | Moins adapté |
|---|---|
| Équipes quantitatives avec stratégie factor investing sur crypto | Stratégies haute fréquence pure (<1ms requis) |
| Startups crypto avec budget limité ($500-2000/mois data) | Casinos DeFi nécessitant données on-chain natives |
| Recherche académique sur pricing dérivées crypto | Trading sur actions/forex traditionnelles |
| Portfolios multi-actifs avec exposition perpetuals | Backtesting sur données tick-by-tick full depth |
| Équipes souhaitant minimiser infrastructure data engineering | Sociétés avec compliance GDPR stricte (données EU required) |
Tarification et ROI
| Plan | Prix mensuel | Rate limit | Cache | Support | Cas d'usage optimal |
|---|---|---|---|---|---|
| Starter | $49/mois | 100 req/min | 10K entries | Prototypage, < 500K candles/mois | |
| Pro | $199/mois | 500 req/min | 100K entries | Chat优先级 | Équipes 2-5 chercheurs, backtesting production |
| Scale-up | $499/mois | 2000 req/min | 1M entries | Slack dédié | Multi-stratégies, 10M+ candles/mois |
| Enterprise | $1,499/mois | Illimité | Personnalisé | Dedicated TAM | Fund proprietary, compliance complète |
ROI détaillé pour équipe type (4 chercheurs + 2 ingénieurs)
Avec le plan Scale-up à $499/mois versus l'ancien fournisseur à $4 200/mois :
- Économie annuelle : ($4 200 - $499) × 12 = $44 412
- Latence améliorée : 420ms → 180ms = 2.3× plus rapide
- Temps de backtest réduit : 8h → 3.5h pour scan 3 ans (scénario TradeFlow)
- ROI temps ingénieur : ~15h/mois récupérées sur maintenance data
Pourquoi choisir HolySheep
Les 5 avantages différenciants
- Latence <50ms garantie : Infrastructure edge optimisée, mesurée en production sur 30 jours à 47ms moyen pour requêtes OHLCV
- Prix 85% inférieurs : Accès aux modèles DeepSeek V3.2 à $0.42/MTok (vs $3+/Tok sur providers traditionnels)
- Multi-paiement fiat : WeChat Pay, Alipay, cartes chinoises acceptées — idéal pour équipes asiatiques
- Cache intelligent natif : 67% de réduction moyenne des appels API, builtin sans configuration
- Crédits gratuits : $10 offert à l'inscription pour tester en conditions réelles
Comparatif technique détaillé
| Feature | HolySheep | Provider A | Provider B |
|---|---|---|---|
| Latence p50 | 47ms | 180ms | 340ms |
| Latence p99 | 120ms | 520ms | 890ms |
| Rate limit starter | 100 req/min | 30 req/min | 60 req/min |
| Cache automatique | ✓ | ✗ | Option payante |
| Data completion | ✓ (0.08% gaps) | ✗ (2.3% gaps) | Partiel |
| Support WeChat/Alipay | ✓ | ✗ | ✗ |
| Prix enterprise | $1,499/mois | $8,000/mois | $5,500/mois |
Erreurs courantes et solutions
Erreur 1 : Rate LimitExceededError (429)
Symptôme : RateLimitError: Rate limit exceeded. Retry after 60s
# Solution : Implémenter exponential backoff avec jitter
import random
import asyncio
async def fetch_with_retry(client, symbol, retries=5):
"""Fetch avec backoff exponentiel"""
for attempt in range(retries):
try:
return await client.fetch_perpetual_ohlcv(symbol)
except RateLimitError as e:
if attempt == retries - 1:
raise
# Backoff : 2^attempt + jitter random
wait_time = (2 ** attempt) + random.uniform(0, 1)
wait_time = min(wait_time, 60) # Max 60s
logger.warning(f"Rate limit, retry dans {wait_time:.2f}s")
await asyncio.sleep(wait_time)
except Exception as e:
logger.error(f"Erreur inattendue: {e}")
raise
Alternative sync avec threading
from threading import Semaphore
class RateLimitedClient:
def __init__(self, client, max_concurrent=10):
self.client = client
self.semaphore = Semaphore(max_concurrent)
def fetch(self, symbol):
with self.semaphore:
return self._fetch_impl(symbol)
Erreur 2 : DataGapError sur gaps de données
Symptôme : DataGapError: Missing 1,247 candles between 1704067200000 and 1704153600000
# Solution : Utiliser data_completion=true + interpolation
class DataCompleter:
"""Fill gaps avec interpolation linéaire"""
def complete_gaps(self, candles: List[Candle], max_gap_size: int = 100) -> List[Candle]:
"""Interpolation des gaps <= max_gap_size candles"""
if len(candles) < 2:
return candles
result = [candles[0]]
for i in range(1, len(candles)):
gap_size = (candles[i].timestamp - candles[i-1].timestamp) // 60000 - 1
if gap_size <= 0:
result.append(candles[i])
elif gap_size <= max_gap_size:
# Interpolation linéaire
interpolated = self._interpolate(candles[i-1], candles[i], gap_size)
result.extend(interpolated)
result.append(candles[i])
else:
# Gap trop large, on garde le gap mais on log
logger.warning(f"Large gap detected: {gap_size} candles at index {i}")
result.append(candles[i])
return result
def _interpolate(self, start: Candle, end: Candle, count: int) -> List[Candle]:
"""Crée count candles interpolées entre start et end"""
dt = (end.timestamp - start.timestamp) / (count + 1)
return [
Candle(
timestamp=int(start.timestamp + dt * (i + 1)),
open=start.open + (end.open - start.open) * (i + 1) / (count + 1),
high=start.high + (end.high - start.high) * (i + 1) / (count + 1),
low=start.low + (end.low - start.low) * (i + 1) / (count + 1),
close=start.close + (end.close - start.close) * (i + 1) / (count + 1),
volume=0, # Volumes interpolés = 0
quote_volume=0,
trades=0
)
for i in range(count)
]
Utilisation
completer = DataCompleter()
complete_candles = completer.complete_gaps(raw_candles)
Erreur 3 : OutOfMemoryError sur gros datasets
Symptôme : MemoryError: Cannot allocate array of size 50M candles
# Solution : Traitement par chunks avec streaming
class StreamingBacktester:
"""Backtest memory-efficient par chunks"""
CHUNK_SIZE = 500_000 # 500K candles par chunk
def __init__(self, client, chunk_size: int = None):
self.client = client
self.chunk_size = chunk_size or self.CHUNK_SIZE
def backtest_streaming(
self,
symbol: str,
start: int,
end: int,
factor_func: callable
) -> dict:
"""Backtest avec processing chunk par chunk"""
total_return = 1.0
positions = []
current_position = 0
current = start