פיתוח מערכת בדיקת אסטרטגיות (Backtesting) לאסטרטגיות DeFi

פיתוח מערכת בדיקת אסטרטגיות (Backtesting) לאסטרטגיות DeFi "האסטרטגיה הראתה 200% APY בבדיקת ה-backtest" — לעתים קרובות משמעות הדבר היא שה-backtest נכתב עם שגיאות. הנפוצה ביותר: האסטרטגיה משתמשת במחיר הסגירה של הנר כדי לקבל החלטת כניסה. זוהי הטיית look-ahead — בזמן אמת

שירותי פיתוח בלוקצ'יין

שאלות נפוצות

העבודות האחרונות

  • image_website-b2b-advance_0.webp
    פיתוח אתר חברה B2B ADVANCE
    1451
  • image_web-applications_feedme_466_0.webp
    פיתוח אפליקציית ווב עבור FEEDME
    1309
  • image_websites_belfingroup_462_0.webp
    פיתוח אתר עבור BELFINGROUP
    1005
  • image_ecommerce_furnoro_435_0.webp
    פיתוח חנות מקוונת לחברת FURNORO
    1270
  • image_logo-advance_0.webp
    עיצוב לוגו לחברת B2B Advance
    719
  • image_crm_enviok_479_0.webp
    פיתוח אפליקציית ווב עבור Enviok
    1011

פיתוח מערכת Backtesting לאסטרטגיות DeFi

"האסטרטגיה הראתה 200% APY בבדיקת ה-backtest" — לעיתים קרובות זה אומר שה-backtest נכתב עם שגיאות. הנפוצה ביותר: האסטרטגיה משתמשת במחיר הסגירה של הנר כדי לקבל החלטת כניסה. זהו הטיה של מבט קדימה (look-ahead bias) — בזמן אמת אינך יודע את מחיר הסגירה של הנר הנוכחי. וריאנט נוסף: ה-backtest מתעלם מעלויות גז ומהחלקה (slippage), מה שהופך אסטרטגיה מפסידה לרווחית על הנייר. אנו בונים מערכות backtesting שמבטלות שגיאות אלו ומתחשבות בכל המציאות של ה-on-chain: מצבי בריכות היסטוריים, שיעורי ריבית אמיתיים של פרוטוקולי הלוואות, והפסדים מעמלות גז.

Backtesting ספציפי ל-DeFi מורכב יותר מ-backtesting פיננסי מסורתי מכיוון שהוא דורש נתוני on-chain: מצבי בריכות היסטוריים, שיעורי ריבית אמיתיים של פרוטוקולי הלוואות, מחיר גז היסטורי, אירועי חיסול (liquidation), והלוואות בזק (flash loans). כל זה משתנה בכל בלוק.

כיצד להימנע מהטיית מבט קדימה ב-backtesting?

הטיית מבט קדימה מבוטלת על ידי הקפדה קפדנית על כרונולוגיית הבלוקים. מנוע ה-backtesting עובר על בלוקים ברצף מההתחלה לסוף, ובכל בלוק האסטרטגיה רואה רק נתונים שהיו זמינים לפני אותו בלוק. לדוגמה, כדי להיכנס על סמך מחיר נר, יש להשתמש במחיר הפתיחה, לא במחיר הסגירה. אם האסטרטגיה משתמשת באינדיקטורים המבוססים על נתונים היסטוריים, הם חייבים להיבנות רק על נתונים שקדמו לבלוק הנוכחי.

מקורות לנתוני on-chain היסטוריים

The Graph וארכיוני subgraph

The Graph מתעד אירועי on-chain מבלוק הפריסה. עבור רוב פרוטוקולי ה-DeFi המרכזיים (Uniswap v2/v3, Aave v2/v3, Compound, Curve) קיימים subgraphs רשמיים עם היסטוריה של כל אירועי ה-swap, ההפקדה וההלוואה.

בעיה: שירות ה-hosted של The Graph יש לו מגבלות קצב (rate limits) ולעיתים מאבד נתונים במהלך reindexing. עבור backtesting רציני, יש צורך ב-Graph Node משלך עם צומת ארכיון של Ethereum, או במקורות מסחריים (Dune Analytics, Flipside Crypto, Goldsky).

Dune Analytics מציע ממשק SQL לנתוני on-chain מפוענחים. זה מאפשר לשאול אירועים של כל חוזה. מגבלה: ה-API לגישה פרוגרמטית יקר (Pro $390/חודש), אבל לבניית מערכי נתונים ייצוא חד-פעמי הוא בחינם.

מקור נתונים סוג גישה מגבלות עלות
The Graph (Hosted) GraphQL 10 בקשות/שנייה חינם (עם הגבלות)
Dune Analytics SQL 1 בקשה/שנייה (חינם) חינם / Pro $390
צומת ארכיון (Alchemy) eth_call 100 אלף בקשות/יום (חינם) תשלום לפי תעבורה

צמתי ארכיון

לא ניתן לקבל חלק מהנתונים מאירועים — יש צורך לקרוא את המצב של בלוק ספציפי. לדוגמה: balanceOf של כתובת בבלוק היסטורי, totalSupply של טוקן, מחיר בבריכת AMM ברגע מסוים. זה דורש צומת ארכיון — היסטוריה מלאה של המצב. Infura, Alchemy, QuickNode מספקות גישת ארכיון דרך eth_call עם פרמטר blockNumber. צומת ארכיון של Ethereum באירוח עצמי דורש 12+ TB ויכול לעלות $5k+ בחומרה.

from web3 import Web3 w3 = Web3(Web3.HTTPProvider(ARCHIVE_RPC_URL)) def get_pool_reserves_at_block(pool_address: str, block_number: int) -> tuple: """Получение резервов Uniswap v2 пула в конкретном блоке""" pool = w3.eth.contract(address=pool_address, abi=UNISWAP_V2_PAIR_ABI) reserves = pool.functions.getReserves().call(block_identifier=block_number) return reserves[0], reserves[1] 

ארכיטקטורת מערכת ה-backtesting

שכבת הנתונים

אנו טוענים ומנרמלים נתונים היסטוריים למסד נתונים מקומי של PostgreSQL. סכמה:

-- Исторические своп события Uniswap v3 CREATE TABLE uniswap_v3_swaps ( block_number BIGINT NOT NULL, block_timestamp TIMESTAMPTZ NOT NULL, tx_hash BYTEA NOT NULL, pool_address VARCHAR(42) NOT NULL, amount0 NUMERIC(78, 0), amount1 NUMERIC(78, 0), sqrt_price_x96 NUMERIC(78, 0), tick INTEGER, liquidity NUMERIC(78, 0), PRIMARY KEY (tx_hash, pool_address) ); -- Исторические lending ставки (Aave) CREATE TABLE aave_rate_history ( block_number BIGINT NOT NULL, block_timestamp TIMESTAMPTZ NOT NULL, asset VARCHAR(42) NOT NULL, liquidity_rate NUMERIC(40, 0), -- RAY variable_borrow_rate NUMERIC(40, 0), utilization_rate NUMERIC(20, 18), PRIMARY KEY (block_number, asset) ); -- Исторический gas price CREATE TABLE gas_price_history ( block_number BIGINT PRIMARY KEY, block_timestamp TIMESTAMPTZ NOT NULL, base_fee_gwei NUMERIC(20, 9), priority_fee_p50 NUMERIC(20, 9) ); 

מנוע הסימולציה

המנוע עובר על בלוקים ברצף, קורא לאסטרטגיה עם נתונים זמינים לכל בלוק:

class BacktestEngine: def __init__(self, strategy: Strategy, start_block: int, end_block: int): self.strategy = strategy self.db = DataLayer() def run(self) -> BacktestResult: portfolio = Portfolio(initial_capital=self.strategy.config.initial_capital) for block_data in self.db.iter_blocks(self.start_block, self.end_block): # Только данные до текущего блока — no look-ahead context = MarketContext( block=block_data, prices=self.db.get_prices_at(block_data.number), lending_rates=self.db.get_rates_at(block_data.number), gas_price=block_data.base_fee + block_data.priority_fee_p50, ) signals = self.strategy.generate_signals(context, portfolio) for signal in signals: # Применяем реалистичное исполнение execution = self.simulate_execution(signal, context) portfolio.apply(execution) return BacktestResult(portfolio=portfolio, metrics=self.compute_metrics(portfolio)) def simulate_execution(self, signal: Signal, ctx: MarketContext) -> Execution: """Учитываем slippage, gas, partial fills""" slippage = self.estimate_slippage(signal.size, ctx.pool_liquidity) gas_cost_usd = ctx.gas_price * signal.estimated_gas * ctx.eth_price / 1e18 executed_price = signal.direction * slippage return Execution( price=executed_price, gas_cost=gas_cost_usd, timestamp=ctx.block.timestamp, ) 

עבור Uniswap v2, ההחלקה היא בערך from web3 import Web3 w3 = Web3(Web3.HTTPProvider(ARCHIVE_RPC_URL)) def get_pool_reserves_at_block(pool_address: str, block_number: int) -> tuple: """Получение резервов Uniswap v2 пула в конкретном блоке""" pool = w3.eth.contract(address=pool_address, abi=UNISWAP_V2_PAIR_ABI) reserves = pool.functions.getReserves().call(block_identifier=block_number) return reserves[0], reserves[1] . עבור v3, המתמטיקה של נזילות מרוכזת מדויקת יותר, אבל הנוסחה של v2 עובדת להערכות מהירות. עבור פרוטוקולי הלוואות, החלקה לא רלוונטית, אבל הפקדות גדולות מורידות את שיעור הניצול (utilization rate) ולכן את ה-APR הבא.

אילו מדדים מראים את יעילות אסטרטגיית DeFi?

לא מספיק להסתכל רק על P&L. הניסיון שלנו (מעל 5 שנים בפיתוח DeFi, 10+ מערכות מיושמות) מראה שהמדדים הקריטיים הם APY מותאם גז, יחסי Sharpe ו-Sortino. APY מותאם גז הוא מדד מפתח עבור DeFi: אסטרטגיה עם 50% APY ו-rebalancing שבועי ברשת הראשית של Ethereum עשויה להיות עם 30% APY מותאם גז, בעוד שב-Arbitrum זה עשוי להיות 45% — זהו הבדל של פי 5 בדיוק לעומת APY גולמי. מנוע הסימולציה שלנו רץ פי 10 מהר יותר מ-backtests טיפוסיים ב-Python, מה שמאפשר סריקות פרמטרים מהירות.

מדד נוסחה אמת מידה
יחס Sharpe (תשואות - סיכון חופשי) / סטיית תקן >1.5 טוב
יחס Sortino (תשואות - סיכון חופשי) / סטיית תקן שלילית >2.0 טוב
גריעה מקסימלית (Max drawdown) שיא לשפל / שיא <30% עבור DeFi
יחס Calmar תשואה שנתית / גריעה מקסימלית >1.0
APY מותאם גז APY פחות עלויות גז תלוי ב-L2

כיצד אנו בונים את המערכת? תהליך ולוח זמנים

אנו מבטיחים נכונות של ה-backtest באמצעות בקרה קפדנית על הטיית מבט קדימה וביצוע ריאלי. העבודה כוללת:

  1. ניתוח אסטרטגיה ובחירת פרוטוקולים
  2. שילוב מקורות נתוני on-chain (The Graph, Dune, צמתי ארכיון)
  3. פיתוח מנוע סימולציה המתחשב בגז והחלקה
  4. יישום מדדים ודשבורד
  5. בדיקות על נתונים היסטוריים
  6. מסירת תיעוד והדרכת צוות

לוח זמנים: מערכת לפרוטוקול אחד אורכת בין שבוע לשבועיים; מערכת רב-פרוטוקולית אורכת בין 4 ל-6 שבועות. הכל נמסר במפתח פתוח (turnkey).

מה כלול בעבודה

  • תיעוד מלא של מסגרת ה-backtesting וכל ההנחות
  • גישה לצינור הנתונים ולמנוע הסימולציה (קוד ומדריך פריסה)
  • הדרכת צוות (עד 4 שעות) על שימוש והרחבת המערכת
  • חודש תמיכה לאחר השקה בחינם

עם מעל 5 שנים בפיתוח DeFi ו-10+ מערכות מיושמות, אנו מספקים פתרונות backtesting חזקים. צרו קשר כדי להעריך את הפרויקט שלכם.

הטיית מבט קדימה — ויקיפדיה החלקה — ויקיפדיה