פיתוח REST API לנתונים היסטוריים: היכן הולכת לאיבוד ההיסטוריה
שירות נתוני שוק היסטוריים נשבר לא כשהוא נופל, אלא כשהוא מחזיר קוד הצלחה עם גוף תשובה חסר. הלקוח מבקש טווח נרות, מקבל תשובה תקינה ובונה עליה חישוב — ובתוך הטווח חסרים כמה מרווחים. חוסרים כאלה בציטוטים אינם נראים בלוגים: לא תקלה, לא עיכוב, פשוט היסטוריה קצרה מהמוצהר.
הסיבה היא בדרך כלל באופן הרכבת התשובה. הנתונים נמשכים בדפים, נתקלים במגבלות הבקשות אצל המקור, חלק מהדפים מגיעים לאחר ניסיונות חוזרים, וחלק — עם סימון שונה של חותמת הזמן.
אם הדפים מודבקים ללא בדיקת רציפות, בצמתים נוצרים חורים, ואזור הזמן ועיגול חותמת הזמן משלימים את התמונה: הנר קיים פורמלית, אבל עומד במקום הלא נכון.
המחיר למוצר אינו קוסמטי. בדיקה היסטורית (בק-טסט) על היסטוריה קרועה מציגה תשואה שלא הייתה, אינדיקטורים מחושבים על חלון חלקי, והדוח אינו תואם את הגרף. מכאן קורסת האמון באנליטיקה, ולהחזיר אותו יקר יותר מתיקון ההגשה.
אנו מפרקים כיצד זה נסגר בפיתוח REST API לנתוני שוק היסטוריים: חוזה על טווח ודיוק חותמת הזמן, בדיקת שלמות ההיסטוריה בכניסה, טעינה מחדש אידמפוטנטית של מה שחסר, מטמון לבקשות חוזרות ומצב הגשה שאינו תלוי במגבלות הבקשות של המקור החיצוני.
מה נותנת שליפת ההיסטוריה: שלמות, מהירות, עמידות
שלמות ההיסטוריה היא הדבר הראשון שבודקים בקבלה. בעבר ציטוטים נלקחו ממקור אחד, ובכלים דקי נזילות נותרו חוסרים בארכיון. כעת שליפת הציטוטים מגיעה ממספר מקורות, הסדרות מובאות לסכימה אחידה, והפערים נסגרים בבקשה חוזרת — דוח איכות מראה אילו קטעים אומתו באופן בלתי תלוי ואילו שוחזרו.
מהירות התגובה נשענת על ויטרינות מחושבות מראש: בקשת טווח טיפוסית מוגשת בשברירי שנייה, ושליפות כבדות עוברות להכנה אסינכרונית של קובץ עם התראה על מוכנות. האחוזון ה-95 של זמן התגובה אינו תלוי עוד במספר השנים שבעבורן התבקשה ההיסטוריה.
עמידות השירות ניתנת על ידי מטמון, הגבלת קצב הפניות למקורות וניסיונות חוזרים עם השהיה מדורגת. אם המקור החיצוני אינו זמין, מוגשת הגרסה העקבית האחרונה של הסדרה, ולא שגיאה — המסוף והאנליטיקה ממשיכים לעבוד. בדיקה בלתי תלויה היא השוואה מול אגרגטורים ציבוריים, לדוגמה CoinMarketCap.
תיקונים ידניים של חוסרים יצאו מתהליך האנליסטים: אי-התאמות בין מקורות מגיעות לדוח, ולא לגרף. הלקוחות בביקורות מציינים בדיוק זאת — "הארכיון הפסיק להיות משימה נפרדת: הנתונים לתקופה הנדרשת מוכנים לתחילת יום המסחר, ולא לאמצעו".
פיתוח REST API: אפשרויות הגשת ההיסטוריה והמגבלות
אותה היסטוריית ציטוטים יכולה להיות מוגשת בארבע דרכים, והבחירה נקבעת לפי פרופיל הצרכן: לשירות בדיקת אסטרטגיות נדרש כל המערך בבת אחת, לרובוט מסחר — זרם רציף, ולאנליטיקאי — חתך שרירותי לפי כלים ותקופות.
אנו מפרידים תרחישים אלה למעגלים נפרדים: מינוי זורם אינו מתחרה על חיבורים עם שליפה מרוכזת, וחתכים כבדים עוברים לרפליקה של המאגר ואינם מאיטים את כתיבת הנתונים החדשים. ההבדל בין המצבים אינו בנוחות, אלא במגבלות שאתם מקבלים יחד איתם.
ארבעה מצבים וגבולותיהם
| מצב | מתי מתאים | מגבלות |
|---|---|---|
| שליפה מדופדפת | אינטגרציות, דוחות, השלמת מרווחים חסרים | מספר הבקשות גדל עם עומק ההיסטוריה; לאחר אתחול נדרש קורסור, אחרת תקבלו כפילויות או חורים |
| שליפה מרוכזת | טעינה ראשונית, בדיקת אסטרטגיות, שחזור ארכיון | הנתונים מפגרים אחרי הרגע הנוכחי; פריסת הקובץ לפי הסכימה שלכם תיעשה בצד הצרכן |
| מינוי זורם | ציטוטים מקוונים, ניטור סיכונים, חישוב אינדיקטורים בזמן אמת | מגיש רק "מרגע זה והלאה"; לאחר ניתוק החיבור נדרש השלמה דרך בקשת היסטוריה |
| שליפה ישירה מהמאגר | אנליטיקה, חתכים שרירותיים, השוואת נתונים | קריאה בלבד ועותק נפרד; הסכימה קבועה, כל שינוי — דרך תיאום |
מגבלות הן תכונה של המצב, ולא פגם: הזרם אינו מגיש עומק, הקובץ אינו מדביק את הזמן האמיתי, והרפליקה אינה כותבת. לכן בתיאור ה-API אנו מקבעים את גבולותיו של כל מצב ואת כללי המעבר ביניהם — השלמה לאחר ניתוק, קורסור בעת אתחול, השוואת נתונים בין העותקים.
מביקורת מקורות ועד מסירה: שלבי העבודה ההנדסית
הפרויקט מתחיל לא בקוד, אלא בניתוח מהיכן מגיעים הנתונים. שליפות מהבורסה, אגרגטורים וארכיונים פנימיים נבדלים ברזולוציה, באזור זמן ובכללי עדכון — כבר כאן נראה אילו סדרות יהיה צורך לאחות, ואילו ניתן להגיש כפי שהן.
- ביקורת מקורות הנתונים. בוחנים את פורמטי השליפה, את עומק ההיסטוריה, את המגבלות על קצב הבקשות ואת התנהגות הפלטפורמה בעת תקלות. בפלט — רשימת מקורות עם סימונים היכן צפויים קרעים וכפילויות.
- תכנון סכימת הנתונים. מקבעים ישויות (עסקאות, נרות, ספר פקודות), אזורי זמן, דיוק העיגול וכללי אחות הסדרות. הסכימה הופכת לחוזה: לפיה נבנים גם המאגר וגם מבנה תשובות ה-API.
- מימוש. בונים שכבת טעינה עם ניסיונות חוזרים וכתיבה אידמפוטנטית, כדי שייבוא חוזר לא ייצור כפילויות, ושכבת הגשה — עם דפדוף מבוסס קורסור וקודי שגיאה צפויים.
- בדיקה על מערך ייחוס. מקטע קטן של היסטוריה מסמנים ידנית ומשווים מול המקור עד הרשומה האחרונה. אי-התאמות נתפסות לפני שהן ממשיכות לאנליטיקה.
- בדיקת קבלה. מריצים את תרחישי הלקוח: כלים נדירים, גבולות תקופות, עומסי שיא. מתעדים שההגשה עומדת בלוחות הזמנים המוסכמים ואינה מאבדת רשומות.
- מסירה ותצפית. מוסרים תיאור סכימה, קונפיגורציה וסדר פריסה, ולאחר ההרצה עוקבים אחר טריות הנתונים ושהיית התגובה.
הסדר אינו מקרי: כל שלב נשען על התוצר של קודמו — רשימת המקורות, הסכימה, מערך הייחוס. לכן הקבלה נסגרת לפני המסירה, ולא אחריה.
מה נשאר אצלכם: מפרט, סכימות, נהלים
שירות נתוני שוק היסטוריים חי יותר מהצוות שהשיק אותו: כעבור חצי שנה יפתח אותו משמרת מהנדסים אחרת — או שלכם, בלי היוצרים בהישג יד. לכן את הממשק העובד אנו מוסרים יחד עם חבילת תוצרים, שלפיהם ניתן לתחזק את השירות בלי לשחזר את הלוגיקה מתוך הקוד.
- מפרט הממשק — מתודות, פרמטרים, פורמטי תשובות, קודי שגיאה ומגבלות פניות בפורמט קריא למכונה: ממנו נוצרים לקוחות ובדיקות.
- סכימת הנתונים — טבלאות, מפתחות, טיפוסים, אינדקסים וכללי אחסון ההיסטוריה; לפיה רואים מדוע שליפה לפי טווח תאריכים נשארת מהירה על נפח גדל.
- נוהל עדכון — לוח זמנים לטעינה, חלון להשלמת תקופות חסרות, בדיקת שלמות והשוואה מול המקור.
- מדיניות גישה — תפקידים ותחומי נראות, תוקף מפתחות, מכסות לצרכן, יומן פניות ונוהל שלילת גישה.
- תיעוד לצוות — הרצה מקומית, משתני סביבה, מיגרציות, מטריקות, צ'ק-ליסט לשחרור ונוהל חזרה לאחור.
- בדיקות אוטומטיות ודוגמאות ייחוס של בקשות — מקבעות את ההתנהגות הצפויה, כדי שתיקונים בפענוח הנתונים ההיסטוריים ייתפסו לפני העלאה.
- הוראות למקרה תקלה — מה לעשות בחוסרים או בתגובות איטיות מהמקור, כיצד לעבור לזרם גיבוי ובמה לאשר את השחזור.
מקרה מעשי: כיצד סגרו חורים בהיסטוריה והאיצו את ההגשה
הפרויקט — אגרגטור של נתוני בורסה: שירות REST API הגיש נרות ועסקאות היסטוריות לאנליטיקה ולרובוטים למסחר. בכניסה, בתקופות מסוימות, חסרו עד 3% מנרות הדקה, והרכבת מערך שנתי לכלי בודד ארכה כארבעים דקות — הלקוחות משכו את ההיסטוריה בדפים ופעמים רבות נקטעו בזמן ההמתנה.
שחזור ההיסטוריה
רפליקות נלקחו ממספר מקורות, כל עסקה הובאה למפתח ראשוני "כלי + חותמת זמן", ואי-התאמות נפתרו בכלל עדיפות המקור. מרווחים חסרים הושלמו מדאמפים ארכיוניים ולוגים, ואגרגטים עבור חלונות שנויים במחלוקת חושבו מחדש. לאחר ההרצה השלמות של סדרת הדקה הגיעה ל-100%, והפערים בין המקורות ירדו לשברי אחוז.
עומס שיא והגשה
תחת שיא השירות גדל קודם בשיהוי: תור הבקשות הצטבר, וחלק מהלקוחות לא המתינו לתשובה על טווחים ארוכים. את הטווחים החמים העברנו למאגר עמודתי ClickHouse, חישבנו מראש אגרגטים שבועיים וחודשיים והגבלנו את גודל הדף. בשיא גבוה פי עשרים מהרגיל ההגשה נשארת יציבה, והרכבת המערך השנתי התקצרה לדקה.
תוצאת הפרויקט: היסטוריה ללא חוסרים, הגשה תחת שיא ללא קטיעות, כללים מתועדים לאיחוד מקורות והרצת שחזור חוזרת על פי לוח זמנים.
במה נבדלת שליפת ההיסטוריה מזרם בזמן אמת
שליפה ארכיונית בממשק REST עונה לבקשה לפי טווח: הלקוח מעביר מרווח זמן ומזהה כלי, והשירות מגיש דף רשומות עם קורסור לדף הבא. התוצאה דטרמיניסטית — חזרה עם אותו קורסור מחזירה את אותן שורות, ולכן ניתוק החיבור נרפא בבקשה חוזרת, ולא בשחזור המינוי.
זרם בזמן אמת בנוי אחרת: המינוי חי בחיבור קבוע, וכל רשומה נמסרת פעם אחת. תקלה כאן אינה חוזרת מעצמה — הודעה שאבדה מושלמת מהיומן לפי חותמת הזמן של הרשומה האחרונה שהתקבלה, אחרת נשאר חור בהיסטוריה. השהיית ההגשה בזרם נמדדת בזנב ההתפלגות, ולא בממוצע: התפרצויות נדירות בשיא הנפח הצרכן מבחין בהן מיד.
מכאן דרישות שונות לאחסון. לארכיון נדרש מערך מלא, מחולק לפי תאריכים, עם אינדקס לפי מפתח וזמן — הוא גדל באופן מונוטוני, ולכן מעבירים אותו למעגל קר, שבו הקריאה יקרה מהכתיבה.
לזרם מספיק חוצץ חם קצר, אך החוצץ חייב לשרוד הפעלה מחדש של הצומת: בלי יומן על הדיסק, המינוי לאחר נפילה מאבד חלון שאי אפשר עוד להרים מהמקור.
השלמת שינויים היא מעגל נפרד. בשליפה ארכיונית מחפים בכוונה על החלון בכמה מרווחים ומשווים את קצוות הטווח, כדי לא לאבד רשומות בגבול. בזרם ההשלמה נעשית לפי קורסור עם מפתח רשומה אידמפוטנטי: כפילויות נחתכות, חוסרים נסגרים.
בשניהם סכומי ביקורת — מספר הרשומות וחותמות הזמן הקיצוניות — נבדקים באופן קבוע, אחרת אי-ההתאמה תצוף כבר בדיווח של הלקוח.
מסקנה מעשית: ממשק אחד יכול להגיש את שני המצבים, אך מאחוריו פועלים שני שירותים שונים עם סכימות אחסון משלהם, מגבלות על עומק הבקשה ותקציב השהיה. התכנון מתחיל בשאלה מה לעשות בעת ניתוק — להריץ מחדש את הטווח או להשלים לפי קורסור. מהתשובה תלויות גם סכימת האחסון וגם האופן שבו תיראה השוואת הנתונים.
ספקות טכניים לפני תחילת העבודה
תקלות וקצוות של נתונים צוותי הנדסה בודקים לפני ההתחלה — והשאלות אצל כולם פחות או יותר אותן: חוסרים, התנהגות בעת כשל של מקור, גבולות ההיסטוריה, השוואה ושליפה. להלן תשובות ישירות, בלי הבטחות ש"הכול יהיה יציב".
מה לעשות עם חוסרים בנתונים ההיסטוריים של המקור?
חוסר אינו ממולא בשקט: הוא מסומן בסמן שלמות מפורש בתשובה, ולא נעלם בין הנקודות הסמוכות. טווח עם פער ניתן לבקש מחדש — ההשלמה החוזרת אידמפוטנטית, וכפילויות אינן נוצרות. נקודת קצה נפרדת מגישה מפת כיסוי לפי כלים ותקופות, כדי שהצרכן יראה את גבולות המהימנות מראש.
מה יקרה אם המקור יפסיק להגיב?
מגישים את החתך המאומת האחרון יחד עם זמן עדכניותו וסמן התיישנות. הצרכן מחליט בעצמו אם לעבוד עם הנתונים הללו או להמתין — במקום תשובה ריקה ופענוח שגיאה בצד שלו.
האם אפשר להרחיב את עומק ההיסטוריה מאוחר יותר?
כן, השלמה היסטורית (בקפיל) נעשית בטווחים ובמנות, חוזה התשובה אינו משתנה — ההרחבה אינה שוברת לקוחות שכבר נכתבו. קטעים חדשים וקטעים שנטענו קודם מושווים בצמתים, כדי שבגבול לא יופיעו ערכים כפולים או סוטים.
כיצד בודקים שהנתונים תואמים את המקור?
ההשוואה נעשית לפי סכומי ביקורת של חתכים בתקופות מדגמיות; אי-התאמות מגיעות לדוח, ולא נמסות בלוגים. זה מעניק שחזוריות: אותו חלון, שנשאל שוב, מחזיר את אותה תוצאה.
האם נוכל לקחת את השליפה שלנו?
השליפה מוגשת בזרם לקובץ לפי אותה סכימת שדות כמו בתשובות ה-REST — הנתונים ניידים ואינם נעולים בתוך השירות. את הפורמט בוחרים בהתאם לקו העיבוד שלכם.
מכאן — דיון: תארו את המשימה, ונחזור עם הערכה ותוכנית.נדון במשימה ונחזור עם הערכה ותוכנית
השיחה הראשונה נדרשת לא לצורך היכרות, אלא כדי לקבע את גבולות העבודה: בלי הבנה של עומק ההיסטוריה, מערך הכלים והשהיית העדכון המותרת, ההערכה הופכת לטווח, וסכימת הנתונים — לעבודה מחדש באמצע הפרויקט. לכן אנו מבררים את מה שנפח העבודה תלוי בו ישירות.
- עומק ההיסטוריה והמקורות: פידים בורסאיים, ארכיונים של ספקים, שליפות עצמאיות — לאיזו תקופה נדרשים הנתונים והיכן ייתכנו חוסרים.
- הרכב הנתונים: טיקים או נרות מצטברים, מרווחים, רשימת כלים ופלטפורמות, והאם נדרש תיקון ציטוטים בגין פיצולי מניות ודיבידנדים.
- דרישות איכות: שלמות הסדרות, דיוק עד לספרה, אזור זמן אחיד, כללים ליישוב אי-התאמות בין מקורות וסינון כפילויות.
- פורמט התשובה וניווט בנפח: JSON, CSV או Parquet; הגשה מדופדפת, קורסורים, מסננים לפי טווח תאריכים וכלי.
- עומס והרשאות: כמה בקשות בו-זמנית מחזיק הצרכן, האם נדרשים מפתחות, הפרדת הרשאות והגבלת קצב הפניות.
- עדכניות ועמידות: באיזו תדירות משלימים נתונים חדשים, תוך כמה זמן סוגרים חוסר בארכיון, ומה רואה הלקוח בעת כשל של המקור.
- קבלה: על אילו מערכים משווים את הפלט למערך הייחוס, ואיזה שיעור בקשות אנו רואים כעומד בזמן התגובה היעד.
תארו את המשימה בצורה חופשית וציינו מה מהמפורט כבר נפתר — נחזור עם הערכת עבודה, סכימת נתונים ותוכנית הטמעה לפי שלבים.







