FX समर्पित VPS / OptiMax उपयोग केस
बैकटेस्ट का रिज़ॉल्यूशन डेटा के रिज़ॉल्यूशन से तय होता है। डेली और ऑवरली कैंडल में जो प्राइस-मूवमेंट संरचना खो जाती है (स्प्रेड के भीतर की हलचल, ऑर्डर-फिल का झुकाव, एक-साथ होने वाले तेज़ उतार-चढ़ाव), वह केवल tick (हर ऑर्डर-फिल का) डेटा में ही बचती है। लेकिन tick का पैमाना ही अलग है। FX के 6 करेंसी पेयर · 2 साल (पूर्ण) के लिए 40 करोड़ से अधिक रिकॉर्ड। इसे “बिना किसी चूक के इकट्ठा करना”, “मेमोरी में लोड करना” और “संपूर्ण (brute-force) रूप से ऑप्टिमाइज़ करना” — सामान्य छोटे VPS के बस की बात नहीं। इस लेख में हम अपने FX समर्पित VPS OptiMax पर शून्य से पूर्ण 2 साल का tick डेटा आधार बनाकर, 64 कोर पर 2,430 रणनीति-पैरामीटर संयोजनों का संपूर्ण अनुकूलन करने तक की पूरी प्रक्रिया, हर अड़चन के साथ वास्तविक मापे गए मानों सहित समझाते हैं।
परीक्षण वातावरण: OptiMax VPS (64 vCPU / 251GB RAM / Ubuntu 24.04)
मापन अवधि: 2023–2024 (पूर्ण 2 वर्ष) / 6 करेंसी पेयर। इस लेख के सभी आँकड़े वास्तविक मापे गए मान हैं।
दायरा: डेटा आधार निर्माण · रेट-लिमिट से बचाव · समानांतर अनुकूलन जैसी सामान्य इंजीनियरिंग तकनीकें ही; इसमें हमारी अपनी सिग्नल रिसर्च की सामग्री शामिल नहीं है।
“tick डेटा × हाई-स्पेक VPS” क्यों ज़रूरी है #
tick “हर बार ऑर्डर फिल होने पर” का सबसे छोटी इकाई का रिकॉर्ड है। स्प्रेड के भीतर क्या हो रहा है, तेज़ उतार-चढ़ाव के समय ऑर्डर-फिल किस ओर झुकते हैं — ऐसी माइक्रो-संरचना कैंडल बनाते ही गायब हो जाती है। इसीलिए शॉर्ट-टर्म रणनीतियों के परीक्षण के लिए tick ज़रूरी है। लेकिन tick का डेटा-वॉल्यूम पैमाने में ही अलग होता है, और संग्रह · भंडारण · गणना — हर जगह मशीन की असली क्षमता परखी जाती है। यह लेख “इकट्ठा कर लिया समझा, पर असल में 80% डेटा गायब था” वाली गलती और उसके सुधार तक, tick डेटा संग्रह में हर किसी के सामने आने वाली खाई को ईमानदारी से साझा करता है।
क्या बनाया (परिणाम) #
| संकेतक | मान |
|---|---|
| अवधि × करेंसी पेयर | पूर्ण 2 वर्ष (2023–2024) × 6 पेयर |
| कुल tick संख्या | 405,616,079 (लगभग 40.6 करोड़) |
| कवरेज दर | ≈100% (ट्रेडिंग समय में शून्य चूक। प्रत्येक पेयर के 15,048 घंटों में से data≈12,473 + बाज़ार-बंद(404)≈2,574, अप्राप्त ≤6) |
| 1-सेकंड बार में | 14.1 करोड़ बार |
| अनुकूलन ट्रायल संख्या | 2,430 संयोजन (सिग्नल × होल्डिंग समय × थ्रेशोल्ड × पेयर, प्रत्येक के साथ bootstrap CI) |
पूरी प्रक्रिया का समय (वास्तविक मापा गया) #
| चरण | समय | टिप्पणी |
|---|---|---|
| ① पूर्ण tick संग्रह (2 क्लीन IP में विभाजन · गैप-फिलिंग) | लगभग 3 घंटे | प्रत्येक संग्राहक मशीन पर 3 पेयर के लिए 10,856 सेकंड, 2 मशीनें समानांतर |
| ② गणना मशीन (OptiMax) पर ट्रांसफ़र (लगभग 1GB) | 51 सेकंड | लगभग 13.6 MB/s |
| ③ विश्लेषण हेतु फ़ॉर्मेट रूपांतरण | 116 सेकंड | npz → parquet |
| ④ 64 कोर पर 2,430 संयोजनों का संपूर्ण अनुकूलन | 581 सेकंड | ग्रिड निर्माण 111s + स्वीप 470s, लगभग 60 कोर उपयोग |
शून्य से लेकर “विश्लेषण-योग्य पूर्ण 2 साल के tick आधार + अनुकूलन परिणाम” तक, वास्तव में 3 घंटे से कुछ अधिक।
STEP 1: डेटा संग्रह ― मुफ़्त feed और “दो खाइयाँ” #
ऐतिहासिक tick, Dukascopy के मुफ़्त डेटा फ़ीड से प्राप्त किया जा सकता है (.bi5 = LZMA संपीड़न + 20-बाइट निश्चित-लंबाई रिकॉर्ड)। 1 घंटा = 1 फ़ाइल, और इसे शुद्ध Python में डिकोड किया जा सकता है।
# .bi5(LZMA + 20B निश्चित-लंबाई: ms_offset, ask, bid, ask_vol, bid_vol)को घंटे-वार समानांतर रूप से प्राप्त करें
import lzma, urllib.request, numpy as np, concurrent.futures as cf
REC = np.dtype([("t",">u4"),("ask",">u4"),("bid",">u4"),("av",">f4"),("bv",">f4")])
def fetch_hour(sym, y, m, d, h):
url = f"https://datafeed.dukascopy.com/datafeed/{sym}/{y:04d}/{m-1:02d}/{d:02d}/{h:02d}h_ticks.bi5"
raw = urllib.request.urlopen(url, timeout=30).read()
return np.frombuffer(lzma.decompress(raw), dtype=REC) # कीमत = points/(JPY के लिए 1000, अन्य के लिए 100000)
खाई①: HTTP 503 (रेट-लिमिट) “कुल मात्रा” से नहीं, “बर्स्ट” से आती है #
गति बढ़ाने के लिए कई मशीनों में बाँटकर, रोकना→तुरंत पुनः शुरू करना बार-बार दोहराने पर, IP पता Dukascopy की ओर से अस्थायी रूप से 503 → कोई प्रतिक्रिया नहीं के साथ ब्लॉक हो गया। परीक्षण का निष्कर्ष:
- 503 का ट्रिगर “कुल अनुरोध मात्रा” नहीं, बल्कि “कम समय में कनेक्शन बर्स्ट” है (= लगातार रोकना-शुरू करना, अत्यधिक समानांतर कनेक्शन)।
- एक बार ब्लॉक होने पर भी, अनुरोध पूरी तरह रोक देने पर 5〜10 मिनट में स्वतः ठीक हो जाता है।
- नियम है “एक ही बार · संयमित समानांतर कनेक्शन से · बिना रुके पूरा बहा दें”। इस बार 1 पेयर 24 थ्रेड × 2 पेयर समानांतर (=48 कनेक्शन) स्थिर दायरा रहा।
खाई②(सबसे महत्वपूर्ण): “साइलेंट ड्रॉप” ― इकट्ठा कर लिया समझा, पर 80% गायब #
पहला संग्रह देखने में “पूरा” लगा, पर बाद में कवरेज मापने पर वह केवल लगभग 22% था। कारण यह था कि डाउनलोडर HTTP 503 को “डेटा नहीं(404)” के समान मानकर चुपचाप फेंक रहा था। ब्लॉक न होने पर भी, व्यस्त समय में हल्के 503 छिटपुट आते रहे, और वे घंटे चुपचाप गायब होते गए। “डेटा बह रहा है = पूर्ण है” — ऐसा नहीं है।
🛠 कैसे पकड़ा, कैसे ठीक किया (पुनरुत्पादन-योग्य चेकलिस्ट)
- पूर्णता को “बह रहा है या नहीं” से नहीं, बल्कि “कवरेज/लॉस दर” से जाँचें। यदि “nonempty दर” ट्रेडिंग समय की अपेक्षा (≈80%) से काफ़ी कम हो तो चूक का संदेह करें। इस बार डाउनस्ट्रीम विश्लेषण में अलाइनमेंट के अत्यधिक सिकुड़ने (5-मिनट पैनल जहाँ मूलतः 1.5 लाख बार होने चाहिए वहाँ केवल 200 के आसपास) से यह उजागर हुआ।
- 404 और 503 में अंतर करें। 404 = वैध बाज़ार-बंद (पुनः प्राप्त न करें), 503/टाइमआउट = पुनः प्राप्ति आवश्यक। जिस क्षण दोनों को एक मान लिया, चूक अदृश्य हो जाती है।
- मल्टी-पास · गैप-फिलिंग। प्रत्येक (दिन, घंटा) के संग्रह परिणाम को रिकॉर्ड करें, और केवल विफल घंटों को एक्सपोनेंशियल बैकऑफ़ से पुनः प्राप्त करें → विफलता 0 होने तक दोहराएँ।
- कवरेज रिपोर्ट से समाप्त करें। “total / data / बाज़ार-बंद(404) / अप्राप्त” अवश्य आउटपुट करें, और अप्राप्त ≈0 तथा ticks/वर्ष अपेक्षा अनुसार है — यह पुष्टि करने के बाद ही भरोसा करें।
परिणामस्वरूप, कवरेज 22% → ≈100% (प्रत्येक पेयर अप्राप्त ≤6 घंटे / 15,048) हो गई। पूर्ण 2 साल के लिए 40.6 करोड़ tick निश्चित रूप से प्राप्त हो गए।
STEP 2: खाई③ मेमोरी ― tick प्रोसेसिंग “RAM-बाउंड” है #
tick का डिकोड, लक्षित दायरे के रिकॉर्ड को एक बार मेमोरी में फैलाकर फिर लिखता है। यानी आवश्यक RAM, अवधि × पेयर संख्या के समानुपाती होती है।
परीक्षण में, 1.9GB RAM वाले छोटे VPS को सहायक रूप में उपयोग करने पर, कई वर्ष × कई पेयर के साथ तुरंत OOM (मेमोरी की कमी से बलपूर्वक समाप्ति)। दूसरी ओर OptiMax (251GB RAM) पर पूर्ण 2 साल × 6 पेयर को पूरा मेमोरी में लोड करने पर भी पर्याप्त जगह (विश्लेषण के पीक पर भी काफ़ी खाली)।
tick डेटा प्रोसेसिंग में, CPU से पहले RAM दीवार बनती है। OptiMax की बड़ी मेमोरी ठीक इसी उपयोग के लिए है।
STEP 3: डिज़ाइन की कुंजी ―”डाउनलोड मशीन” और “गणना मशीन” को अलग करें #
- डाउनलोड में लाइन क्वालिटी (Dukascopy तक का रूट) प्रमुख होती है।
- विश्लेषण · अनुकूलन में RAM और कोर संख्या प्रमुख होती है।
ये अलग-अलग मशीनों की खूबियाँ हैं, इसलिए भूमिकाएँ बाँट दीं। इस बार क्लीन IP वाली 2 संग्राहक मशीनों से डेटा इकट्ठा किया (प्रति-IP रेट-लिमिट को दोगुना टालना = विभाजन का असली लाभ), और OptiMax को “गणना का मातृ-जहाज़” बनाकर ट्रांसफ़र · एकत्रीकरण · अनुकूलन पर केंद्रित रखा। लगभग 1GB का ट्रांसफ़र मात्र 51 सेकंड। किसी भी बॉटलनेक से बँधे नहीं रहते।
STEP 4: 64 कोर पर “रणनीति का संपूर्ण अनुकूलन” #
यहीं OptiMax की असली ताक़त है। MT5 के स्ट्रैटेजी-टेस्टर अनुकूलन जैसी ही सोच से, 1 ट्रायल = 1 कोर आवंटित करके सभी कोर का पूरा उपयोग करते हैं।
मुख्य बात है समानांतरीकरण की इकाई। केवल “करेंसी पेयर” से समानांतर करने पर मात्र 6 कोर चलते हैं। (पेयर × सिग्नल × होल्डिंग समय × एंट्री थ्रेशोल्ड) के सभी संयोजनों को 1 ट्रायल बनाने पर ट्रायल संख्या एकदम बढ़ जाती है और 64 कोर पूरे भर जाते हैं। भारी प्री-प्रोसेसिंग (1-सेकंड ग्रिड) एक ही बार बनाकर साझा करते हैं।
# भारी प्री-प्रोसेसिंग(1-सेकंड ग्रिड) केवल 1 बार → fork pool से साझा(copy-on-write) → सभी संयोजनों का संपूर्ण अनुकूलन
import multiprocessing as mp
GRIDS = {p: build_grid(p) for p in PAIRS} # पैरेंट प्रोसेस में केवल एक बार निर्माण(COW से चाइल्ड को साझा)
tasks = [(p,sig,H,thr) for p in PAIRS for sig in SIGNALS for H in HORIZONS for thr in THRESHOLDS]
with mp.Pool(64) as pool:
results = pool.map(eval_combo, tasks) # प्रत्येक combo = walk-forward + लागत-समायोजन + bootstrap CI
वास्तविक माप: 14.1 करोड़ 1-सेकंड बार पर 2,430 संयोजन, लगभग 60 कोर उपयोग · 581 सेकंड (ग्रिड निर्माण 111s + स्वीप 470s) में पूरे। प्रत्येक ट्रायल में walk-forward (समय-शृंखला का प्रशिक्षण→सत्यापन विभाजन) + राउंड-ट्रिप स्प्रेड घटाकर लागत-समायोजित PnL + ब्लॉक-bootstrap विश्वास-अंतराल तक शामिल पूर्ण सत्यापन है।
“बैकटेस्ट है इसलिए सभी कोर उपयोग नहीं हो सकते” — यह ग़लतफ़हमी है। समानांतरीकरण की इकाई को “पैरामीटर संयोजन” बना दें तो अनुकूलन कोर संख्या के अनुपात में सीधे तेज़ होता है। OptiMax के 64 कोर यहाँ सचमुच पूरी क्षमता से चलते हैं।
परिणाम (सामान्य सीख) #
पूर्ण 2 साल · 40.6 करोड़ tick · 2,430 अनुकूलन ट्रायल के मात्रात्मक परिणाम:
- सिग्नल स्वयं “मौजूद” है: लागत-रहित (GROSS) शार्प अनुपात अधिकतम +429। शॉर्ट-टर्म प्राइस-मूवमेंट में वाक़ई संरचना है।
- पर टेकर (मार्केट ऑर्डर) से कमाया नहीं जा सकता: राउंड-ट्रिप स्प्रेड घटाने पर, 2,430 में से एक भी प्लस नहीं होता (NET>0 केवल 0/2,430)। इतना ही नहीं, प्रत्येक ट्रायल की 95% विश्वास-अंतराल की ऊपरी सीमा तक भी 0/2,430 ही प्लस — यानी सांख्यिकीय रूप से भी “प्लस हो सकने वाला” संयोजन शून्य (डेटा को पूर्ण करने से शोर-जनित “तुक्के वाले पॉज़िटिव” भी मिट गए)।
- यह बाज़ार माइक्रो-संरचना का पाठ्यपुस्तक-परिणाम (शॉर्ट-टर्म एज bid-ask स्प्रेड के भीतर ही सिमट जाती है, और स्प्रेड चुकाने वाला = टेकर उसे वसूल नहीं पाता) — को बड़े पैमाने · पूर्ण डेटा पर कठोरता से पुनः पुष्ट करता है।
व्यावहारिक निहितार्थ: शॉर्ट-टर्म एज की रिसर्च “लागत घटाने के बाद” ही सार्थक होती है। और उस बड़े पैमाने के सत्यापन को व्यावहारिक समय में चलाने के लिए पूर्ण डेटा · RAM · कोर संख्या चाहिए।
सारांश #
| क्या किया | निर्णायक तत्व |
|---|---|
| पूर्ण 2 साल · 40.6 करोड़ tick का संग्रह | संयमित समानांतरण + 404/503 भेद + मल्टी-पास · गैप-फिलिंग से कवरेज 22%→100% |
| 40 करोड़ tick को मेमोरी में फैलाकर प्रोसेसिंग | 251GB RAM (छोटे VPS पर OOM) |
| 2,430 संयोजनों का संपूर्ण अनुकूलन | 64 कोर + “संयोजन-इकाई समानांतरीकरण” |
| पूरी प्रक्रिया | वास्तव में 3 घंटे से कुछ अधिक |
tick-स्तर का बड़े पैमाने का बैकटेस्ट · अनुकूलन अब किसी विशेष कंप्यूटर पर एकाधिकार की माँग नहीं करता। OptiMax VPS से, जब चाहिए तब उतनी ही RAM और कोर लेकर इस पैमाने का सत्यापन व्यावहारिक समय में चलाया जा सकता है। डेटा संग्रह की खाइयाँ (503 बर्स्ट · साइलेंट ड्रॉप · RAM सीमा) भी इस लेख की चेकलिस्ट से टाली जा सकती हैं।
यह पूरा परीक्षण OptiMax VPS (64 vCPU / 251GB RAM) पर किया गया।
बड़ी मेमोरी · अनेक कोर · कम लेटेंसी, जब चाहिए तब उतनी ही। FX ऑटोमेटेड ट्रेडिंग से लेकर क्वांट रिसर्च तक।