{"id":28371,"date":"2026-08-27T09:21:51","date_gmt":"2026-08-27T09:21:51","guid":{"rendered":"https:\/\/umang.pk\/2026\/08\/27\/%d9%85%d8%a7%d8%b1%da%a9%db%8c%d9%b9-%d9%b9%d8%a7%d8%a6%d9%85-%d9%85%d8%b4%db%8c%d9%86-%d8%a8%d9%86%d8%a7%d9%86%d8%a7-%d8%a7%d8%b2%da%af%d8%b1-%d8%a7%d9%88%d8%b1-%d9%88%db%8c%d8%a8-%d8%b3%d8%a7%da%a9\/"},"modified":"2026-08-27T09:21:52","modified_gmt":"2026-08-27T09:21:52","slug":"%d9%85%d8%a7%d8%b1%da%a9%db%8c%d9%b9-%d9%b9%d8%a7%d8%a6%d9%85-%d9%85%d8%b4%db%8c%d9%86-%d8%a8%d9%86%d8%a7%d9%86%d8%a7-%d8%a7%d8%b2%da%af%d8%b1-%d8%a7%d9%88%d8%b1-%d9%88%db%8c%d8%a8-%d8%b3%d8%a7%da%a9","status":"publish","type":"post","link":"https:\/\/umang.pk\/ur\/2026\/08\/27\/%d9%85%d8%a7%d8%b1%da%a9%db%8c%d9%b9-%d9%b9%d8%a7%d8%a6%d9%85-%d9%85%d8%b4%db%8c%d9%86-%d8%a8%d9%86%d8%a7%d9%86%d8%a7-%d8%a7%d8%b2%da%af%d8%b1-%d8%a7%d9%88%d8%b1-%d9%88%db%8c%d8%a8-%d8%b3%d8%a7%da%a9\/","title":{"rendered":"\u0645\u0627\u0631\u06a9\u06cc\u0679 \u0679\u0627\u0626\u0645 \u0645\u0634\u06cc\u0646 \u0628\u0646\u0627\u0646\u0627: \u0627\u0632\u06af\u0631 \u0627\u0648\u0631 \u0648\u06cc\u0628 \u0633\u0627\u06a9\u0679 \u06a9\u0627 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631\u062a\u06d2 \u06c1\u0648\u0626\u06d2 \u0679\u0631\u06cc\u0688\u0646\u06af \u0633\u06cc\u0634\u0646 \u06a9\u0648 \u062f\u0648\u0628\u0627\u0631\u06c1 \u0686\u0644\u0627\u0626\u06cc\u06ba"},"content":{"rendered":"\n<div id=\"\">\n<p>\u062a\u0627\u0631\u06cc\u062e\u06cc \u0645\u0627\u0631\u06a9\u06cc\u0679 \u06a9\u0627 \u0688\u06cc\u0679\u0627 \u0639\u0627\u0645 \u0637\u0648\u0631 \u067e\u0631 \u0627\u06cc\u06a9 \u0645\u06a9\u0645\u0644 \u0688\u06cc\u0679\u0627\u0633\u06cc\u0679 \u06a9\u06d2 \u0637\u0648\u0631 \u067e\u0631 \u0622\u062a\u0627 \u06c1\u06d2\u06d4 \u06cc\u06c1 \u062a\u062c\u0632\u06cc\u06c1 \u06a9\u06d2 \u0644\u06cc\u06d2 \u0622\u0633\u0627\u0646 \u06c1\u06d2\u060c \u0644\u06cc\u06a9\u0646 \u06cc\u06c1 \u0627\u0633 \u0633\u06d2 \u0628\u06c1\u062a \u0645\u062e\u062a\u0644\u0641 \u06c1\u06d2 \u06a9\u06c1 \u06a9\u0633 \u0637\u0631\u062d \u0679\u0631\u06cc\u0688\u0646\u06af \u0633\u0627\u0641\u0679 \u0648\u06cc\u0626\u0631 \u062d\u0642\u06cc\u0642\u06cc \u0645\u0627\u0631\u06a9\u06cc\u0679\u0648\u06ba \u06a9\u0627 \u062a\u062c\u0631\u0628\u06c1 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4 \u067e\u06cc\u062f\u0627\u0648\u0627\u0631 \u0645\u06cc\u06ba\u060c \u0648\u0627\u0642\u0639\u0627\u062a \u0627\u06cc\u06a9 \u0648\u0642\u062a \u0645\u06cc\u06ba \u06c1\u0648\u062a\u06d2 \u06c1\u06cc\u06ba\u060c \u0645\u0633\u062a\u0642\u0628\u0644 \u0646\u0627\u0645\u0639\u0644\u0648\u0645 \u06c1\u06d2\u060c \u0627\u0648\u0631 \u062a\u0645\u0627\u0645 \u0641\u06cc\u0635\u0644\u06d2 \u0635\u0631\u0641 \u0627\u0633 \u0628\u0627\u062a \u067e\u0631 \u0645\u0646\u062d\u0635\u0631 \u06c1\u06cc\u06ba \u06a9\u06c1 \u0627\u0628 \u062a\u06a9 \u06a9\u06cc\u0627 \u06c1\u0648\u0627 \u06c1\u06d2\u06d4<\/p>\n<p>\u0627\u0633 \u0679\u06cc\u0648\u0679\u0648\u0631\u06cc\u0644 \u0645\u06cc\u06ba\u060c \u06c1\u0645 \u0627\u0633 \u062a\u062c\u0631\u0628\u06d2 \u06a9\u0648 \u062f\u0648\u0628\u0627\u0631\u06c1 \u0628\u0646\u0627\u0646\u06d2 \u06a9\u06d2 \u0644\u06cc\u06d2 \u062a\u0627\u0631\u06cc\u062e\u06cc \u0679\u06a9 \u0688\u06cc\u0679\u0627 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631\u06cc\u06ba \u06af\u06d2\u06d4 \u06c1\u0645 EODHD \u0633\u06d2 \u0627\u06cc\u06a9 \u067e\u0648\u0631\u0627 AAPL \u0679\u0631\u06cc\u0688\u0646\u06af \u0633\u06cc\u0634\u0646 \u0644\u06cc\u06ba \u06af\u06d2\u060c \u0627\u06cc\u06a9 \u0645\u0644\u06cc\u0646 \u0633\u06d2 \u0632\u06cc\u0627\u062f\u06c1 \u0679\u0631\u06cc\u0688\u0632 \u06a9\u0648 \u0627\u06cc\u06a9 \u0688\u06cc\u0679\u0631\u0645\u0646\u0633\u0679\u06a9 \u0627\u06cc\u0648\u0646\u0679 \u0679\u06cc\u067e \u0645\u06cc\u06ba \u0645\u0639\u0645\u0648\u0644 \u0628\u0646\u0627\u0626\u06cc\u06ba \u06af\u06d2\u060c \u0627\u0648\u0631 \u0627\u0633\u06d2 \u0642\u0627\u0628\u0644 \u06a9\u0646\u0679\u0631\u0648\u0644 \u0645\u0627\u0631\u06a9\u06cc\u0679 \u06a9\u0644\u0627\u06a9 \u06a9\u06d2 \u0630\u0631\u06cc\u0639\u06d2 \u0627\u0633 \u06a9\u06d2 \u0627\u0635\u0644 \u0648\u0642\u062a \u06a9\u06d2 \u0645\u0637\u0627\u0628\u0642 \u062f\u0648\u0628\u0627\u0631\u06c1 \u0686\u0644\u0627\u0626\u06cc\u06ba \u06af\u06d2\u06d4<\/p>\n<p>\u0631\u0627\u0633\u062a\u06d2 \u0645\u06cc\u06ba\u060c \u06c1\u0645 \u067e\u0644\u06d2 \u0628\u06cc\u06a9 \u06a9\u06cc \u0631\u0641\u062a\u0627\u0631 \u06a9\u0648 \u0627\u06cc\u0688\u062c\u0633\u0679 \u06a9\u0631\u06cc\u06ba \u06af\u06d2\u060c \u06a9\u0646\u0679\u0631\u0648\u0644\u0632 \u06a9\u0648 \u0631\u0648\u06a9\u06cc\u06ba \u06af\u06d2 \u0627\u0648\u0631 \u062f\u0648\u0628\u0627\u0631\u06c1 \u0634\u0631\u0648\u0639 \u06a9\u0631\u06cc\u06ba \u06af\u06d2\u060c \u062a\u0644\u0627\u0634 \u06a9\u0631\u06cc\u06ba \u06af\u06d2\u060c \u0627\u0648\u0631 \u0627\u06cc\u06a9 FastAPI \u0633\u0631\u0648\u0633 \u062c\u0648 WebSockets \u067e\u0631 \u0679\u0631\u0627\u0646\u0632\u06cc\u06a9\u0634\u0646\u0632 \u06a9\u0648 \u0627\u0633\u0679\u0631\u06cc\u0645 \u06a9\u0631\u062a\u06d2 \u06c1\u0648\u0626\u06d2 REST \u067e\u0631 \u06a9\u0646\u0679\u0631\u0648\u0644 \u06a9\u0648 \u0638\u0627\u06c1\u0631 \u06a9\u0631\u062a\u06cc \u06c1\u06d2\u06d4<\/p>\n<p>\u06c1\u0645 \u0627\u06cc\u06a9 \u0639\u0644\u06cc\u062d\u062f\u06c1 \u0635\u0627\u0631\u0641 \u0628\u06be\u06cc \u0628\u0646\u0627\u0626\u06cc\u06ba \u06af\u06d2 \u062c\u0648 \u0635\u0631\u0641 \u0645\u0648\u0635\u0648\u0644 \u06c1\u0648\u0646\u06d2 \u0648\u0627\u0644\u06d2 \u0648\u0627\u0642\u0639\u0627\u062a \u067e\u0631 \u0631\u0648\u0644\u0646\u06af VWAP \u0627\u0648\u0631 \u0645\u0627\u0631\u06a9\u06cc\u0679 \u06a9\u06cc \u062d\u0627\u0644\u062a \u06a9\u0627 \u062d\u0633\u0627\u0628 \u0644\u06af\u0627\u062a\u0627 \u06c1\u06d2\u06d4 \u0622\u062e\u0631 \u06a9\u0627\u0631\u060c \u06c1\u0645\u0627\u0631\u06d2 \u067e\u0627\u0633 \u0627\u06cc\u06a9 \u0645\u06a9\u0645\u0644 \u0637\u0648\u0631 \u067e\u0631 \u0645\u0642\u0627\u0645\u06cc \u0631\u06cc \u067e\u0644\u06d2 \u0633\u0633\u0679\u0645 \u06c1\u0648\u06af\u0627 \u062c\u0648 \u067e\u06c1\u0644\u06d2 \u0633\u06d2 \u0645\u06a9\u0645\u0644 \u06c1\u0648\u0646\u06d2 \u0648\u0627\u0644\u06d2 \u062a\u062c\u0627\u0631\u062a\u06cc \u062f\u0646\u0648\u06ba \u06a9\u0648 \u0627\u06cc\u06a9 \u0679\u0627\u0626\u0645 \u0633\u0679\u0631\u06cc\u0645 \u06a9\u06d2 \u0637\u0648\u0631 \u067e\u0631 \u0627\u06cc\u0648\u0646\u0679 \u0633\u06d2 \u0686\u0644\u0646\u06d2 \u0648\u0627\u0644\u06d2 \u0633\u0627\u0641\u0679 \u0648\u06cc\u0626\u0631 \u06a9\u0648 \u0641\u06cc\u0688 \u06a9\u0631 \u0633\u06a9\u062a\u0627 \u06c1\u06d2\u060c \u062c\u0628\u06a9\u06c1 \u0628\u0627\u0632\u06cc\u0627\u0641\u062a \u06a9\u06d2 \u0628\u0639\u062f \u0646\u06cc\u0686\u06d2 \u06a9\u06cc \u062f\u06be\u0627\u0631\u06d2 \u06a9\u06cc \u062d\u0627\u0644\u062a \u06a9\u0648 \u062f\u0631\u0633\u062a \u0637\u0631\u06cc\u0642\u06d2 \u0633\u06d2 \u062f\u0648\u0628\u0627\u0631\u06c1 \u0628\u0646\u0627\u062a\u0627 \u06c1\u06d2 \u0627\u0648\u0631 \u062e\u0648\u062f\u06a9\u0627\u0631 \u062c\u0627\u0646\u0686 \u06a9\u06d2 \u0630\u0631\u06cc\u0639\u06d2 \u0646\u062a\u0627\u0626\u062c \u06a9\u06cc \u062a\u0648\u062b\u06cc\u0642 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<h2 id=\"heading-table-of-contents\">\u0627\u0646\u0688\u06cc\u06a9\u0633<\/h2>\n<h2 id=\"heading-prerequisites\">\u0634\u0631\u0627\u0626\u0637<\/h2>\n<p>\u0634\u0631\u0648\u0639 \u06a9\u0631\u0646\u06d2 \u0633\u06d2 \u067e\u06c1\u0644\u06d2\u060c \u062f\u0631\u062c \u0630\u06cc\u0644 \u06a9\u0648 \u0686\u06cc\u06a9 \u06a9\u0631\u06cc\u06ba:<\/p>\n<ul>\n<li>\n<p>Python 3.10 \u06cc\u0627 \u0627\u0633 \u0633\u06d2 \u0632\u06cc\u0627\u062f\u06c1 \u0627\u0646\u0633\u0679\u0627\u0644 \u06c1\u06d2\u06d4<\/p>\n<\/li>\n<li>\n<p>\u062a\u0627\u0631\u06cc\u062e\u06cc \u0679\u06a9 \u0688\u06cc\u0679\u0627 \u0627\u06cc\u0646\u0688 \u067e\u0648\u0627\u0626\u0646\u0679 \u062a\u06a9 \u0631\u0633\u0627\u0626\u06cc \u06a9\u06d2 \u0644\u06cc\u06d2 EODHD API \u06a9\u0644\u06cc\u062f\u06d4 \u0622\u067e EODHD \u0642\u06cc\u0645\u062a\u0648\u06ba \u06a9\u06d2 \u0635\u0641\u062d\u06c1 \u067e\u0631 \u0627\u06cc\u06a9 \u0688\u0648\u06cc\u0644\u067e\u0631 \u0627\u06a9\u0627\u0624\u0646\u0679 \u0628\u0646\u0627 \u0633\u06a9\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4<\/p>\n<\/li>\n<li>\n<p>\u0679\u0631\u0645\u06cc\u0646\u0644 \u0627\u0648\u0631 \u06a9\u0648\u0688 \u0627\u06cc\u0688\u06cc\u0679\u0631\u06d4<\/p>\n<\/li>\n<li>\n<p>\u0628\u0646\u06cc\u0627\u062f\u06cc Python \u0639\u0644\u0645\u060c \u0628\u0634\u0645\u0648\u0644 \u0641\u0646\u06a9\u0634\u0646\u0632\u060c \u06a9\u0644\u0627\u0633\u0632\u060c \u0644\u063a\u0627\u062a \u0627\u0648\u0631 \u067e\u06cc\u06a9\u062c\u0632 \u06a9\u06d2 \u0633\u0627\u062a\u06be \u06a9\u0627\u0645 \u06a9\u0631\u0646\u0627\u06d4<\/p>\n<\/li>\n<li>\n<p>HTTP \u0627\u0648\u0631 WebSockets \u06a9\u0627 \u0628\u0646\u06cc\u0627\u062f\u06cc \u0639\u0644\u0645 \u06a9\u0648\u0626\u06cc \u0633\u0627\u0628\u0642\u06c1 \u200b\u200bFastAPI \u062a\u062c\u0631\u0628\u06c1 \u062f\u0631\u06a9\u0627\u0631 \u0646\u06c1\u06cc\u06ba \u06c1\u06d2\u06d4<\/p>\n<\/li>\n<li>\n<p>\u0688\u0627\u0624\u0646 \u0644\u0648\u0688 \u06a9\u0631\u062f\u06c1 \u062e\u0627\u0645 \u0679\u06a9 \u0688\u06cc\u0679\u0627 \u0627\u0648\u0631 \u067e\u0631\u0648\u0633\u06cc\u0633 \u0634\u062f\u06c1 \u067e\u0644\u06d2 \u0628\u06cc\u06a9 \u0679\u06cc\u067e\u0633 \u06a9\u0648 \u0630\u062e\u06cc\u0631\u06c1 \u06a9\u0631\u0646\u06d2 \u06a9\u06d2 \u0644\u06cc\u06d2 \u06a9\u0627\u0641\u06cc \u0645\u0642\u0627\u0645\u06cc \u0688\u0633\u06a9 \u06a9\u06cc \u062c\u06af\u06c1\u06d4 \u0627\u0633 \u0679\u06cc\u0648\u0679\u0648\u0631\u06cc\u0644 \u0645\u06cc\u06ba \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06c1\u0648\u0646\u06d2 \u0648\u0627\u0644\u06d2 \u0645\u06a9\u0645\u0644 AAPL \u0633\u06cc\u0634\u0646 \u0645\u06cc\u06ba 10 \u0644\u0627\u06a9\u06be \u0633\u06d2 \u0632\u06cc\u0627\u062f\u06c1 \u0644\u06cc\u0646 \u062f\u06cc\u0646 \u06a9\u06d2 \u0631\u06cc\u06a9\u0627\u0631\u0688 \u0634\u0627\u0645\u0644 \u06c1\u06cc\u06ba\u06d4<\/p>\n<\/li>\n<\/ul>\n<p>\u0627\u0633 \u0679\u06cc\u0648\u0679\u0648\u0631\u06cc\u0644 \u0645\u06cc\u06ba \u0634\u06cc\u0644 \u06a9\u0645\u0627\u0646\u0688\u0632 \u06cc\u0648\u0646\u06a9\u0633 \u0637\u0631\u0632 \u06a9\u0627 \u0646\u062d\u0648 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631\u062a\u06cc \u06c1\u06cc\u06ba\u060c \u0644\u06c1\u0630\u0627 \u0648\u06c1 \u0628\u0631\u0627\u06c1 \u0631\u0627\u0633\u062a \u0645\u06cc\u06a9 \u0627\u0648 \u0627\u06cc\u0633 \u0627\u0648\u0631 \u0644\u06cc\u0646\u06a9\u0633 \u067e\u0631 \u06a9\u0627\u0645 \u06a9\u0631\u062a\u06cc \u06c1\u06cc\u06ba\u06d4 \u0648\u0646\u0688\u0648\u0632 \u067e\u0631\u060c \u0622\u067e \u0627\u0633\u06d2 WSL\u060c Git Bash \u06a9\u06d2 \u0630\u0631\u06cc\u0639\u06d2 \u0686\u0644\u0627 \u0633\u06a9\u062a\u06d2 \u06c1\u06cc\u06ba\u060c \u06cc\u0627 \u0645\u0633\u0627\u0648\u06cc PowerShell \u06a9\u0645\u0627\u0646\u0688\u0632 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631 \u0633\u06a9\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4<\/p>\n<h2 id=\"heading-what-were-building\">\u06c1\u0645 \u06a9\u06cc\u0627 \u0628\u0646\u0627 \u0631\u06c1\u06d2 \u06c1\u06cc\u06ba<\/h2>\n<p>\u06a9\u0633\u06cc \u06a9\u0648\u0688 \u06a9\u0648 \u0686\u06be\u0648\u0646\u06d2 \u0633\u06d2 \u067e\u06c1\u0644\u06d2 \u067e\u0648\u0631\u06d2 \u0633\u0633\u0679\u0645 \u067e\u0631 \u0627\u06cc\u06a9 \u0646\u0638\u0631 \u0688\u0627\u0644\u0646\u0627 \u0645\u0641\u06cc\u062f \u06c1\u06d2\u06d4 \u067e\u0644\u06d2 \u0628\u06cc\u06a9 \u0627\u0646\u062c\u0646 EODHD \u0633\u06d2 \u062a\u0627\u0631\u06cc\u062e\u06cc \u0644\u06cc\u0646 \u062f\u06cc\u0646 \u0644\u06cc\u062a\u0627 \u06c1\u06d2\u060c \u0627\u0646\u06c1\u06cc\u06ba \u0627\u06cc\u06a9 \u0645\u0633\u062a\u0642\u0644 \u0627\u0646\u062f\u0631\u0648\u0646\u06cc \u0634\u06a9\u0644 \u0645\u06cc\u06ba \u062a\u0628\u062f\u06cc\u0644 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u060c \u0679\u0627\u0626\u0645\u0646\u06af \u06a9\u0648 \u0628\u062d\u0627\u0644 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u060c \u0627\u0648\u0631 \u062a\u062c\u0627\u0631\u062a\u06cc \u062f\u0646 \u06a9\u06d2 \u062f\u0648\u0628\u0627\u0631\u06c1 \u06a9\u06be\u0644\u062a\u06d2 \u06c1\u06cc \u0627\u0646\u06c1\u06cc\u06ba \u0635\u0627\u0631\u0641\u06cc\u0646 \u06a9\u06d2 \u0644\u06cc\u06d2 \u0627\u0644\u06af \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<p>\u0645\u06a9\u0645\u0644 \u0628\u06c1\u0627\u0624 \u0645\u0646\u062f\u0631\u062c\u06c1 \u0630\u06cc\u0644 \u06c1\u06d2:<\/p>\n<p>\u06c1\u0631 \u067e\u0631\u062a \u06a9\u0627 \u0627\u06cc\u06a9 \u06a9\u0627\u0645 \u06c1\u0648\u062a\u0627 \u06c1\u06d2\u06d4 \u0644\u0648\u0688\u0631 \u062e\u0627\u0645 \u062a\u0627\u0631\u06cc\u062e\u06cc \u0633\u06cc\u0634\u0646\u0632 \u06a9\u0648 \u0628\u0627\u0632\u06cc\u0627\u0641\u062a \u0627\u0648\u0631 \u0645\u062d\u0641\u0648\u0638 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4 \u0646\u0627\u0631\u0645\u0644\u0627\u0626\u0632\u0631 \u0631\u06cc\u06a9\u0627\u0631\u0688 \u06a9\u06cc \u062a\u0648\u062b\u06cc\u0642 \u06a9\u0631\u062a\u0627 \u06c1\u06d2 \u0627\u0648\u0631 \u0627\u0633\u06d2 \u0688\u06cc\u0679\u0631\u0645\u0646\u0633\u0679\u06a9 \u067e\u0644\u06d2 \u0628\u06cc\u06a9 \u0679\u06cc\u067e \u0645\u06cc\u06ba \u062a\u0628\u062f\u06cc\u0644 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4 \u06af\u06be\u0691\u06cc\u0627\u06ba \u0646\u0642\u0634\u06c1 \u0631\u06cc\u06a9\u0627\u0631\u0688\u0646\u06af \u0679\u0627\u0626\u0645 \u0627\u0633\u0679\u06cc\u0645\u067e \u06a9\u0648 \u0648\u0627\u0644 \u06a9\u0644\u0627\u06a9 \u0679\u0627\u0626\u0645 \u06a9\u06d2 \u0645\u0637\u0627\u0628\u0642 \u06a9\u0631\u062a\u06cc \u06c1\u06cc\u06ba\u060c \u062c\u0628\u06a9\u06c1 \u067e\u0644\u06d2 \u0628\u06cc\u06a9 \u0633\u06cc\u0634\u0646\u0632 \u06a9\u0646\u0679\u0631\u0648\u0644\u0632 \u06a9\u0648 \u0634\u0627\u0645\u0644 \u06a9\u0631\u062a\u06d2 \u06c1\u06cc\u06ba \u062c\u06cc\u0633\u06d2 \u06a9\u06c1 \u0627\u0633\u0679\u0627\u0631\u0679\u060c \u0645\u0648\u0642\u0648\u0641\u060c \u062f\u0648\u0628\u0627\u0631\u06c1 \u0634\u0631\u0648\u0639\u060c \u0631\u0641\u062a\u0627\u0631 \u062a\u0628\u062f\u06cc\u0644 \u06a9\u0631\u0646\u0627\u060c \u062a\u0644\u0627\u0634 \u06a9\u0631\u0646\u0627 \u0627\u0648\u0631 \u0631\u06a9\u0646\u0627\u06d4<\/p>\n<p>\u0641\u0627\u0633\u0679 \u0627\u06d2 \u067e\u06cc \u0622\u0626\u06cc \u0627\u0633 \u067e\u0644\u06d2 \u0628\u06cc\u06a9 \u0627\u0646\u062c\u0646 \u06a9\u06d2 \u0627\u0631\u062f \u06af\u0631\u062f \u0628\u06cc\u0679\u06be\u062a\u0627 \u06c1\u06d2\u06d4 REST \u0627\u06cc\u0646\u0688 \u067e\u0648\u0627\u0626\u0646\u0679\u0633 \u06a9\u0646\u0679\u0631\u0648\u0644 \u06c1\u0648\u0627\u0626\u06cc \u062c\u06c1\u0627\u0632 \u0628\u0646\u0627\u062a\u06d2 \u06c1\u06cc\u06ba\u060c \u0627\u0648\u0631 WebSockets \u0627\u0635\u0644 \u0644\u06cc\u0646 \u062f\u06cc\u0646 \u0627\u0648\u0631 \u067e\u0644\u06d2 \u0628\u06cc\u06a9 \u06a9\u0646\u0679\u0631\u0648\u0644 \u0627\u06cc\u0648\u0646\u0679\u0633 \u06a9\u0648 \u0644\u06d2 \u062c\u0627\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4 \u062f\u0648\u0633\u0631\u06cc \u0637\u0631\u0641\u060c \u0635\u0627\u0631\u0641\u06cc\u0646 \u0627\u067e\u0646\u06cc \u0631\u0648\u0644\u0646\u06af \u0633\u0679\u06cc\u0679 \u06a9\u0648 \u0635\u0631\u0641 \u0627\u0633 \u0633\u0679\u0631\u06cc\u0645 \u06a9\u06d2 \u0630\u0631\u06cc\u0639\u06d2 \u067e\u06c1\u0646\u0686\u0646\u06d2 \u0648\u0627\u0644\u06cc \u0686\u06cc\u0632\u0648\u06ba \u0633\u06d2 \u0628\u0631\u0642\u0631\u0627\u0631 \u0631\u06a9\u06be\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4<\/p>\n<p>\u06c1\u0645 \u0627\u0646 \u0630\u0645\u06c1 \u062f\u0627\u0631\u06cc\u0648\u06ba \u06a9\u0648 \u067e\u0631\u0627\u062c\u06cc\u06a9\u0679 \u06a9\u06d2 \u0688\u06be\u0627\u0646\u0686\u06d2 \u0645\u06cc\u06ba \u0627\u0644\u06af \u0631\u06a9\u06be\u06cc\u06ba \u06af\u06d2\u06d4<\/p>\n<pre><code class=\"language-plaintext\">market-time-machine\/\n\u251c\u2500\u2500 data\/\n\u2502   \u251c\u2500\u2500 raw\/\n\u2502   \u2514\u2500\u2500 processed\/\n\u251c\u2500\u2500 replay\/\n\u2502   \u251c\u2500\u2500 __init__.py\n\u2502   \u251c\u2500\u2500 config.py\n\u2502   \u251c\u2500\u2500 loader.py\n\u2502   \u251c\u2500\u2500 events.py\n\u2502   \u251c\u2500\u2500 clock.py\n\u2502   \u2514\u2500\u2500 session.py\n\u251c\u2500\u2500 api\/\n\u2502   \u251c\u2500\u2500 __init__.py\n\u2502   \u251c\u2500\u2500 server.py\n\u2502   \u2514\u2500\u2500 run.py\n\u251c\u2500\u2500 consumer\/\n\u2502   \u251c\u2500\u2500 __init__.py\n\u2502   \u2514\u2500\u2500 consumer.py\n\u251c\u2500\u2500 tests\/\n\u2502   \u251c\u2500\u2500 __init__.py\n\u2502   \u251c\u2500\u2500 conftest.py\n\u2502   \u2514\u2500\u2500 test_replay.py\n\u251c\u2500\u2500 .env\n\u251c\u2500\u2500 .gitignore\n\u2514\u2500\u2500 pytest.ini\n<\/code><\/pre>\n<p>\u067e\u0648\u0631\u06cc \u062a\u0639\u0645\u06cc\u0631 \u06a9\u06d2 \u0644\u06cc\u06d2 \u0627\u06c1\u0645 \u0627\u0635\u0648\u0644 \u0622\u0633\u0627\u0646 \u06c1\u06d2: \u0635\u0627\u0631\u0641\u06cc\u0646 \u06a9\u0648 \u0635\u0631\u0641 \u06cc\u06c1 \u062c\u0627\u0646\u0646\u06d2 \u06a9\u06cc \u0636\u0631\u0648\u0631\u062a \u06c1\u06d2 \u06a9\u06c1 \u067e\u0644\u06d2 \u0628\u06cc\u06a9 \u0627\u0633\u0679\u0631\u06cc\u0645 \u06a9\u06d2 \u0630\u0631\u06cc\u0639\u06d2 \u067e\u06c1\u0644\u06d2 \u0633\u06d2 \u06a9\u06cc\u0627 \u067e\u06c1\u0646\u0686 \u0686\u06a9\u0627 \u06c1\u06d2\u06d4 \u062a\u0627\u0631\u06cc\u062e \u06a9\u06d2 \u0679\u06cc\u067e \u06a9\u0648 \u067e\u06c1\u0644\u06d2 \u0633\u06d2 \u0646\u06c1\u06cc\u06ba \u067e\u0691\u06be\u0646\u0627 \u0686\u0627\u06c1\u06cc\u06d2\u06d4 \u06cc\u06c1 \u0631\u06a9\u0627\u0648\u0679\u06cc\u06ba \u06c1\u06cc\u06ba \u062c\u0648 \u067e\u0648\u0633\u0679 \u0646\u06cc\u0648\u06cc\u06af\u06cc\u0634\u0646 \u0679\u0627\u0626\u0645\u0646\u06af\u060c \u0645\u0648\u0642\u0648\u0641\/\u062f\u0648\u0628\u0627\u0631\u06c1 \u0634\u0631\u0648\u0639 \u06a9\u0631\u0646\u06d2 \u06a9\u06d2 \u0631\u0648\u06cc\u06d2\u060c \u0627\u0648\u0631 \u0631\u06cc\u0627\u0633\u062a \u06a9\u06cc \u062a\u0634\u06a9\u06cc\u0644 \u0646\u0648 \u06a9\u0648 \u0635\u062d\u06cc\u062d \u0637\u0631\u06cc\u0642\u06d2 \u0633\u06d2 \u0644\u0627\u06af\u0648 \u06a9\u0631\u0646\u06d2 \u06a9\u06d2 \u0642\u0627\u0628\u0644 \u0628\u0646\u0627\u062a\u06cc \u06c1\u06cc\u06ba\u06d4<\/p>\n<h2 id=\"heading-set-up-the-python-project\">\u0627\u0632\u06af\u0631 \u067e\u0631\u0648\u062c\u06cc\u06a9\u0679 \u06a9\u06cc \u062a\u0631\u062a\u06cc\u0628\u0627\u062a<\/h2>\n<p>\u0627\u06cc\u06a9 \u067e\u0631\u0648\u062c\u06cc\u06a9\u0679 \u0688\u0627\u0626\u0631\u06a9\u0679\u0631\u06cc \u0628\u0646\u0627 \u06a9\u0631 \u0627\u0648\u0631 \u0627\u0646 \u067e\u06cc\u06a9\u06cc\u062c\u0632 \u06a9\u0648 \u0627\u0646\u0633\u0679\u0627\u0644 \u06a9\u0631\u06a9\u06d2 \u0634\u0631\u0648\u0639 \u06a9\u0631\u06cc\u06ba \u062c\u0646\u06c1\u06cc\u06ba \u0622\u067e \u0688\u06cc\u0679\u0627 \u06a9\u06cc \u0628\u0627\u0632\u06cc\u0627\u0641\u062a\u060c \u067e\u0644\u06d2 \u0628\u06cc\u06a9 \u0679\u0627\u0626\u0645\u0646\u06af\u060c API \u0644\u06cc\u0626\u0631\u060c \u0648\u06cc\u0628 \u0633\u0627\u06a9\u0679 \u06a9\u0645\u06cc\u0648\u0646\u06cc\u06a9\u06cc\u0634\u0646\u060c \u0627\u0648\u0631 \u0679\u06cc\u0633\u0679\u0646\u06af \u06a9\u06d2 \u0644\u06cc\u06d2 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631\u06cc\u06ba \u06af\u06d2\u06d4<\/p>\n<pre><code class=\"language-shell\">mkdir -p market-time-machine\/data\/raw\nmkdir -p market-time-machine\/data\/processed\nmkdir -p market-time-machine\/replay\nmkdir -p market-time-machine\/api\nmkdir -p market-time-machine\/consumer\nmkdir -p market-time-machine\/tests\n\ncd market-time-machine\n\npip install requests fastapi \"uvicorn[standard]\" websockets httpx python-dotenv numpy pytest pytest-asyncio\n<\/code><\/pre>\n<p>\u0627\u06cc\u06a9 \u0688\u0628\u06c1 \u0628\u0646\u0627\u0646\u0627 <code>__init__.py<\/code> \u0627\u0646\u062f\u0631 \u0641\u0627\u0626\u0644 <code>replay<\/code>, <code>api<\/code>, <code>consumer<\/code>\u0627\u0648\u0631 <code>tests<\/code> \u0644\u06c1\u0630\u0627\u060c \u0627\u0632\u06af\u0631 \u06c1\u0631 \u0688\u0627\u0626\u0631\u06cc\u06a9\u0679\u0631\u06cc \u06a9\u0648 \u0627\u06cc\u06a9 \u067e\u06cc\u06a9\u062c \u06a9\u06d2 \u0637\u0648\u0631 \u067e\u0631 \u062f\u06cc\u06a9\u06be\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<pre><code class=\"language-plaintext\">replay\/__init__.py\napi\/__init__.py\nconsumer\/__init__.py\ntests\/__init__.py\n<\/code><\/pre>\n<p>\u0686\u0648\u0646\u06a9\u06c1 \u06c1\u0645 \u0645\u0627\u0636\u06cc \u06a9\u06d2 \u0644\u06cc\u0646 \u062f\u06cc\u0646 \u06a9\u0648 EODHD \u0633\u06d2 \u062f\u0631\u0622\u0645\u062f \u06a9\u0631\u06cc\u06ba \u06af\u06d2\u06d4 <code>.env<\/code> \u0641\u0627\u0626\u0644 \u06a9\u0648 \u0627\u067e\u0646\u06d2 \u067e\u0631\u0648\u062c\u06cc\u06a9\u0679 \u06a9\u06cc \u062c\u0691 \u0645\u06cc\u06ba \u0645\u062d\u0641\u0648\u0638 \u06a9\u0631\u06cc\u06ba \u0627\u0648\u0631 \u0627\u067e\u0646\u06cc API \u06a9\u0644\u06cc\u062f \u06a9\u0648 \u0648\u06c1\u0627\u06ba \u0645\u062d\u0641\u0648\u0638 \u06a9\u0631\u06cc\u06ba\u06d4<\/p>\n<p>\u0686\u0648\u0646\u06a9\u06c1 \u0688\u0627\u0624\u0646 \u0644\u0648\u0688 \u06a9\u0631\u062f\u06c1 \u0633\u06cc\u0634\u0646\u0632 \u0628\u06be\u06cc \u06a9\u0627\u0641\u06cc \u0628\u0691\u06d2 \u06c1\u06cc\u06ba\u060c \u0627\u0633 \u0644\u06cc\u06d2 \u0622\u067e \u06a9\u0648 \u06a9\u0633\u06cc \u0628\u06be\u06cc \u0627\u0633\u0646\u0627\u062f \u06cc\u0627 \u0645\u0642\u0627\u0645\u06cc \u0645\u0627\u0631\u06a9\u06cc\u0679 \u0688\u06cc\u0679\u0627 \u0641\u0627\u0626\u0644\u0648\u06ba \u06a9\u0627 \u0627\u0631\u062a\u06a9\u0627\u0628 \u0646\u06c1\u06cc\u06ba \u06a9\u0631\u0646\u0627 \u0686\u0627\u06c1\u06cc\u06d2\u06d4 \u0628\u0646\u0627\u0646\u0627 <code>.gitignore<\/code>:<\/p>\n<pre><code class=\"language-plaintext\">.env\ndata\/\n__pycache__\/\n*.pyc\n.ipynb_checkpoints\/\n<\/code><\/pre>\n<p><strong>\u0645\u06cc\u0645\u0648:<\/strong> \u0627\u06af\u0631 \u0622\u067e \u06a9\u06d2 \u067e\u0627\u0633 EODHD API \u06a9\u0644\u06cc\u062f \u0646\u06c1\u06cc\u06ba \u06c1\u06d2\u060c \u062a\u0648 \u0622\u067e EODHD \u0688\u0648\u06cc\u0644\u067e\u0631 \u0627\u06a9\u0627\u0624\u0646\u0679 \u06a9\u06be\u0648\u0644 \u06a9\u0631 \u0622\u0633\u0627\u0646\u06cc \u0633\u06d2 \u062d\u0627\u0635\u0644 \u06a9\u0631 \u0633\u06a9\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4<\/p>\n<h4 id=\"heading-after-this-setup-the-project-should-look-like-this\">\u0627\u0633 \u0633\u06cc\u0679 \u0627\u067e \u06a9\u06d2 \u0628\u0639\u062f\u060c \u0622\u067e \u06a9\u0627 \u067e\u0631\u0648\u062c\u06cc\u06a9\u0679 \u0627\u0633 \u0637\u0631\u062d \u0646\u0638\u0631 \u0622\u0646\u0627 \u0686\u0627\u06c1\u06cc\u06d2:<\/h4>\n<pre><code class=\"language-plaintext\">market-time-machine\/\n\u251c\u2500\u2500 data\/\n\u2502   \u251c\u2500\u2500 raw\/\n\u2502   \u2514\u2500\u2500 processed\/\n\u251c\u2500\u2500 replay\/\n\u2502   \u2514\u2500\u2500 __init__.py\n\u251c\u2500\u2500 api\/\n\u2502   \u2514\u2500\u2500 __init__.py\n\u251c\u2500\u2500 consumer\/\n\u2502   \u2514\u2500\u2500 __init__.py\n\u251c\u2500\u2500 tests\/\n\u2502   \u2514\u2500\u2500 __init__.py\n\u251c\u2500\u2500 .env\n\u2514\u2500\u2500 .gitignore\n<\/code><\/pre>\n<p>\u06a9\u06c1 <code>raw\/<\/code> \u0688\u0627\u0626\u0631\u06cc\u06a9\u0679\u0631\u06cc EODHD \u0633\u06d2 \u0645\u0648\u0635\u0648\u0644 \u06c1\u0648\u0646\u06d2 \u0648\u0627\u0644\u06d2 \u062c\u0648\u0627\u0628\u0627\u062a \u06a9\u0648 \u0645\u062d\u0641\u0648\u0638 \u0631\u06a9\u06be\u062a\u06cc \u06c1\u06d2\u060c \u0644\u06cc\u06a9\u0646 <code>processed\/<\/code> \u06c1\u0645 \u0627\u067e\u0646\u06d2 \u0628\u0646\u0627\u0626\u06d2 \u06c1\u0648\u0626\u06d2 \u0639\u0627\u0645 \u067e\u0644\u06d2 \u0628\u06cc\u06a9 \u0679\u06cc\u067e\u0633 \u06a9\u0648 \u0631\u06a9\u06be\u06cc\u06ba \u06af\u06d2\u06d4<\/p>\n<h2 id=\"heading-download-a-full-trading-session-from-eodhd\">EODHD \u0633\u06d2 \u0645\u06a9\u0645\u0644 \u062a\u062c\u0627\u0631\u062a\u06cc \u0633\u06cc\u0634\u0646 \u0688\u0627\u0624\u0646 \u0644\u0648\u0688 \u06a9\u0631\u06cc\u06ba\u06d4<\/h2>\n<p>\u067e\u0644\u06d2 \u0628\u06cc\u06a9 \u0627\u0646\u062c\u0646 \u06a9\u06d2 \u0644\u06cc\u06d2 \u0648\u0642\u062a \u06a9\u0627 \u0627\u062d\u0633\u0627\u0633 \u0628\u062d\u0627\u0644 \u06a9\u0631\u0646\u06d2 \u06a9\u06d2 \u0644\u06cc\u06d2 \u0627\u06cc\u06a9 \u0645\u06a9\u0645\u0644 \u062a\u062c\u0627\u0631\u062a\u06cc \u0633\u06cc\u0634\u0646 \u062f\u0631\u06a9\u0627\u0631 \u06c1\u06d2\u06d4 \u06c1\u0645 15 \u062c\u0648\u0644\u0627\u0626\u06cc 2026 \u06a9\u06d2 \u0644\u06cc\u06d2 AAPL \u0679\u0631\u0627\u0646\u0632\u06cc\u06a9\u0634\u0646\u0632 \u06a9\u0648 \u0628\u0627\u0632\u06cc\u0627\u0641\u062a \u06a9\u0631\u0646\u06d2 \u06a9\u06d2 \u0644\u06cc\u06d2 EODHD \u06a9\u0627 \u062a\u0627\u0631\u06cc\u062e\u06cc \u0679\u06a9 API \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631\u062a\u06d2 \u06c1\u06cc\u06ba\u060c \u0644\u06cc\u06a9\u0646 \u062a\u0644\u0627\u0634 \u06a9\u06cc \u067e\u0631\u062a \u06a9\u0648 \u067e\u0644\u06d2 \u0628\u06cc\u06a9 \u0633\u06d2 \u0645\u062a\u0639\u0644\u0642 \u06a9\u0633\u06cc \u0628\u06be\u06cc \u0686\u06cc\u0632 \u0633\u06d2 \u0627\u0644\u06af \u0631\u06a9\u06be\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4<\/p>\n<p>\u062f\u0648 \u0641\u0627\u0626\u0644\u06cc\u06ba \u067e\u0631\u0648\u062c\u06cc\u06a9\u0679 \u06a9\u06d2 \u0627\u0633 \u062d\u0635\u06d2 \u06a9\u0648 \u0633\u0646\u0628\u06be\u0627\u0644\u062a\u06cc \u06c1\u06cc\u06ba\u06d4<\/p>\n<pre><code class=\"language-plaintext\">market-time-machine\/\n\u2514\u2500\u2500 replay\/\n    \u251c\u2500\u2500 __init__.py\n    \u251c\u2500\u2500 config.py\n    \u2514\u2500\u2500 loader.py\n<\/code><\/pre>\n<p><code>config.py<\/code>    \u0645\u0634\u062a\u0631\u06a9\u06c1 APIs\u060c \u0631\u0648\u0679\u0633\u060c \u0627\u0648\u0631 \u0645\u0627\u0631\u06a9\u06cc\u0679 \u0633\u06cc\u0634\u0646 \u06a9\u06cc \u062a\u0631\u062a\u06cc\u0628\u0627\u062a \u06a9\u0648 \u0627\u06cc\u06a9 \u062c\u06af\u06c1 \u067e\u0631 \u0631\u06a9\u06be\u06cc\u06ba\u06d4 <code>loader.py<\/code> \u06c1\u0645 \u0627\u0646 \u062a\u0631\u062a\u06cc\u0628\u0627\u062a \u06a9\u0648 \u0633\u06cc\u0634\u0646 \u06a9\u0648 \u0628\u0627\u0632\u06cc\u0627\u0641\u062a \u06a9\u0631\u0646\u06d2 \u0627\u0648\u0631 \u0646\u06cc\u0686\u06d2 \u062f\u06cc\u0626\u06d2 \u06af\u0626\u06d2 \u062e\u0627\u0645 \u062c\u0648\u0627\u0628 \u06a9\u0648 \u0645\u062d\u0641\u0648\u0638 \u06a9\u0631\u0646\u06d2 \u06a9\u06d2 \u0644\u06cc\u06d2 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4 <code>data\/raw\/<\/code>.<\/p>\n<h3 id=\"heading-create-replayconfigpy\">\u0628\u0646\u0627\u0646\u0627 <code>replay\/config.py<\/code><\/h3>\n<p>\u062f\u0631\u062c \u0630\u06cc\u0644 \u0634\u0627\u0645\u0644 \u06a9\u0631\u06cc\u06ba:<\/p>\n<pre><code class=\"language-python\">import os\nfrom pathlib import Path\nfrom dotenv import load_dotenv\n\nROOT = Path(__file__).resolve().parent.parent\nload_dotenv(ROOT \/ \".env\")\n\nTOKEN = os.environ.get(\"EODHD_API_TOKEN\")\nTICKS_URL = \"https:\/\/eodhd.com\/api\/ticks\/\"\n\nRAW = ROOT \/ \"data\" \/ \"raw\"\nPROCESSED = ROOT \/ \"data\" \/ \"processed\"\n\nMARKET_TZ = \"America\/New_York\"\nOPEN = \"09:30:00\"\nCLOSE = \"16:00:00\"\n\nMAX_LIMIT = 10_000\nMIN_WINDOW_S = 1\nCLOSE_GRACE_S = 5\n\nFIELDS = (\"mkt\", \"price\", \"seq\", \"shares\", \"sl\", \"sub_mkt\", \"ts\")\nNON_LAST_SALE = frozenset(\"IWVT47\")\n\ndef token():\n    if not TOKEN:\n        raise RuntimeError(\"EODHD_API_TOKEN not set\")\n    return TOKEN\n\ndef redact(text):\n    return str(text).replace(TOKEN, \"<token>\") if TOKEN else str(text)\n<\/token><\/code><\/pre>\n<p>\u0627\u06cc\u06a9 \u0628\u0627\u0642\u0627\u0639\u062f\u06c1 \u0627\u0645\u0631\u06cc\u06a9\u06cc \u0627\u0633\u0679\u0627\u06a9 \u0633\u06cc\u0634\u0646 \u06a9\u06cc \u0648\u0636\u0627\u062d\u062a \u0627\u0633 \u0637\u0631\u062d \u06a9\u06cc \u06af\u0626\u06cc \u06c1\u06d2: <code>America\/New_York<\/code> \u06cc\u06c1 \u0636\u0631\u0648\u0631\u06cc \u06c1\u06d2 \u06a9\u06cc\u0648\u0646\u06a9\u06c1 UTC 09:30 \u06a9\u06d2 \u0645\u0633\u0627\u0648\u06cc \u06cc\u0648 \u0679\u06cc \u0633\u06cc \u0679\u0627\u0626\u0645 \u0627\u0633\u0679\u06cc\u0645\u067e \u06a9\u06d2 \u0628\u062c\u0627\u0626\u06d2 \u062f\u0646 \u06a9\u06cc \u0631\u0648\u0634\u0646\u06cc \u06a9\u06cc \u0628\u0686\u062a \u06a9\u06d2 \u0648\u0642\u062a \u06a9\u06d2 \u0633\u0627\u062a\u06be \u062a\u0628\u062f\u06cc\u0644 \u06c1\u0648\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<p>\u06c1\u0645 \u062f\u0631\u062e\u0648\u0627\u0633\u062a \u06a9\u06cc \u0645\u062f\u062a \u06a9\u0648 16:00 \u0633\u06d2 5 \u0633\u06cc\u06a9\u0646\u0688 \u062a\u06a9 \u0628\u0691\u06be\u0627\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4 <code>CLOSE_GRACE_S<\/code>. \u0627\u0633 \u0679\u06cc\u0648\u0679\u0648\u0631\u06cc\u0644 \u0645\u06cc\u06ba \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06c1\u0648\u0646\u06d2 \u0648\u0627\u0644\u06d2 \u0633\u06cc\u0634\u0646 \u0645\u06cc\u06ba \u0627\u06cc\u0633\u06cc \u0633\u0631\u06af\u0631\u0645\u06cc \u06c1\u0648\u062a\u06cc \u06c1\u06d2 \u062c\u0648 16:00:00 \u06a9\u06d2 \u0641\u0648\u0631\u0627\u064b \u0628\u0639\u062f \u062e\u062a\u0645 \u06c1\u0648 \u062c\u0627\u062a\u06cc \u06c1\u06d2\u060c \u0627\u0633 \u0644\u06cc\u06d2 \u0631\u0639\u0627\u06cc\u062a\u06cc \u0645\u062f\u062a \u0627\u0633 \u062a\u0627\u0631\u06cc\u062e \u06a9\u0648 \u0688\u0627\u0624\u0646 \u0644\u0648\u0688 \u06a9\u06d2 \u0627\u0646\u062f\u0631 \u0628\u0631\u0642\u0631\u0627\u0631 \u0631\u06a9\u06be\u062a\u06cc \u06c1\u06d2\u06d4<\/p>\n<h3 id=\"heading-create-replayloaderpy\">\u0628\u0646\u0627\u0646\u0627 <code>replay\/loader.py<\/code><\/h3>\n<p>\u0627\u06cc\u06a9 \u0628\u0691\u06cc \u062f\u0631\u062e\u0648\u0627\u0633\u062a \u0679\u06a9 \u0688\u06cc\u0679\u0627 \u06a9\u06d2 \u06af\u06be\u0646\u06d2 \u0633\u06cc\u0634\u0646 \u06a9\u0648 \u0628\u0627\u0632\u06cc\u0627\u0641\u062a \u06a9\u0631\u0646\u06d2 \u06a9\u0627 \u0645\u062d\u0641\u0648\u0638 \u0637\u0631\u06cc\u0642\u06c1 \u0646\u06c1\u06cc\u06ba \u06c1\u06d2\u06d4 \u0633\u0631\u06af\u0631\u0645\u06cc \u067e\u0648\u0631\u06d2 \u062f\u0646 \u0645\u06cc\u06ba \u0646\u0645\u0627\u06cc\u0627\u06ba \u0637\u0648\u0631 \u067e\u0631 \u062a\u0628\u062f\u06cc\u0644 \u06c1\u0648\u062a\u06cc \u06c1\u06d2\u060c \u0627\u0648\u0631 \u06a9\u0648\u0626\u06cc \u0628\u06be\u06cc \u062f\u0631\u062e\u0648\u0627\u0633\u062a \u062c\u0648 \u062a\u0631\u062a\u06cc\u0628 \u0634\u062f\u06c1 \u062a\u06a9 \u067e\u06c1\u0646\u0686 \u062c\u0627\u062a\u06cc \u06c1\u06d2\u06d4 <code>10,000<\/code>-\u0631\u06cc\u06a9\u0627\u0631\u0688 \u06a9\u06cc \u062d\u062f\u06cc\u06ba \u06a9\u0679\u06d2 \u06c1\u0648\u0626\u06d2 \u0648\u0642\u0641\u0648\u06ba \u06a9\u06cc \u0646\u0634\u0627\u0646\u062f\u06c1\u06cc \u06a9\u0631 \u0633\u06a9\u062a\u06cc \u06c1\u06cc\u06ba\u06d4<\/p>\n<p>\u0627\u0633 \u06a9\u06d2 \u0628\u062c\u0627\u0626\u06d2\u060c \u0644\u0648\u0688\u0631 \u067e\u0686\u06be\u0644\u06d2 \u062c\u0648\u0627\u0628\u0627\u062a \u06a9\u06cc \u06a9\u062b\u0627\u0641\u062a \u06a9\u06cc \u0628\u0646\u06cc\u0627\u062f \u067e\u0631 \u0627\u067e\u0646\u06cc \u062f\u0631\u062e\u0648\u0627\u0633\u062a \u06a9\u06cc \u0648\u0646\u0688\u0648 \u06a9\u0648 \u0627\u06cc\u0688\u062c\u0633\u0679 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<p>\u0628\u0646\u0627\u0646\u0627 <code>replay\/loader.py<\/code>:<\/p>\n<pre><code class=\"language-python\">import json, time\nfrom datetime import datetime\nfrom zoneinfo import ZoneInfo\n\nimport requests\n\nfrom . import config\n\ndef fetch(symbol, frm, to, limit=None):\n    limit = limit or config.MAX_LIMIT\n\n    r = requests.get(config.TICKS_URL, timeout=180, params={\n        \"s\": symbol,\n        \"from\": frm,\n        \"to\": to,\n        \"limit\": limit,\n        \"api_token\": config.token(),\n        \"fmt\": \"json\"\n    })\n\n    if r.status_code != 200:\n        raise RuntimeError(\n            f\"HTTP {r.status_code} {config.redact(r.text[:200])}\"\n        )\n\n    return r.json()\n\ndef bounds(date_str, grace=None):\n    grace = config.CLOSE_GRACE_S if grace is None else grace\n    tz = ZoneInfo(config.MARKET_TZ)\n    d = datetime.strptime(date_str, \"%Y-%m-%d\").date()\n\n    def at(hms):\n        h, m, s = map(int, hms.split(\":\"))\n        return datetime(\n            d.year, d.month, d.day, h, m, s, tzinfo=tz\n        ).timestamp()\n\n    return int(at(config.OPEN)), int(at(config.CLOSE)) + grace\n\ndef fetch_session(symbol, date_str, tag=\"session\", window=None,\n                  force=False, verbose=True):\n\n    raw = config.RAW \/ f\"{symbol}_{date_str}_{tag}.jsonl\"\n    man = config.RAW \/ f\"{symbol}_{date_str}_{tag}.manifest.json\"\n\n    if raw.exists() and man.exists() and not force:\n        m = json.loads(man.read_text())\n        print(f\"cached {raw.name}: {m['ticks']:,} ticks\")\n        return m, raw\n\n    start, end = window or bounds(date_str)\n    cursor, win = start, 30\n\n    total = pages = retries = 0\n    first_ts = last_ts = None\n    seen_fields = set()\n    t0 = time.perf_counter()\n\n    with open(raw, \"w\") as fh:\n        while cursor < end:\n            b = min(cursor + win, end)\n            span = b - cursor\n\n            payload = fetch(symbol, cursor, b)\n            n = len(payload.get(\"ts\", []))\n\n            if n >= config.MAX_LIMIT:\n                if span <= config.MIN_WINDOW_S:\n                    raise RuntimeError(\n                        f\"second {cursor} has >= {config.MAX_LIMIT} ticks \"\n                        \"and cannot be paginated\"\n                    )\n\n                win = max(1, span \/\/ 2)\n                retries += 1\n                continue\n\n            if n:\n                seen_fields.update(payload.keys())\n\n                if first_ts is None:\n                    first_ts = payload[\"ts\"][0]\n\n                last_ts = payload[\"ts\"][-1]\n\n                fh.write(json.dumps({\n                    \"from\": cursor,\n                    \"to\": b,\n                    \"payload\": payload\n                }) + \"n\")\n\n            total += n\n            pages += 1\n            cursor = b\n\n            density = n \/ span if span else 0\n            win = int(min(\n                1800,\n                max(1, config.MAX_LIMIT * 0.75 \/ max(density, 0.01))\n            ))\n\n            if verbose and pages % 20 == 0:\n                pct = 100 * (cursor - start) \/ (end - start)\n                print(f\"{pct:5.1f}% {total:,} ticks\")\n\n    m = {\n        \"symbol\": symbol,\n        \"date\": date_str,\n        \"tag\": tag,\n        \"ticks\": total,\n        \"pages\": pages,\n        \"retries\": retries,\n        \"window_from_utc\": start,\n        \"window_to_utc\": end,\n        \"first_timestamp_ms\": first_ts,\n        \"last_timestamp_ms\": last_ts,\n        \"fields\": sorted(seen_fields),\n        \"elapsed_s\": round(time.perf_counter() - t0, 1),\n        \"api_calls\": pages * 10\n    }\n\n    man.write_text(json.dumps(m, indent=2))\n    return m, raw\n\ndef read_pages(path):\n    with open(path) as fh:\n        for line in fh:\n            if line.strip():\n                yield json.loads(line)\n<\/code><\/pre>\n<p>\u0644\u0648\u0688\u0631 30 \u0633\u06cc\u06a9\u0646\u0688 \u06a9\u06cc \u0645\u062f\u062a \u06a9\u06d2 \u0633\u0627\u062a\u06be \u0634\u0631\u0648\u0639 \u06c1\u0648\u062a\u0627 \u06c1\u06d2\u06d4 \u0627\u06af\u0631 \u0648\u06c1 \u0648\u0642\u0641\u06c1 \u0631\u06cc\u06a9\u0627\u0631\u0688 \u06a9\u06cc \u0628\u0627\u0644\u0627\u0626\u06cc \u062d\u062f \u062a\u06a9 \u067e\u06c1\u0646\u0686 \u062c\u0627\u062a\u0627 \u06c1\u06d2\u060c \u062a\u0648 \u06cc\u06c1 \u0645\u0645\u06a9\u0646\u06c1 \u0637\u0648\u0631 \u067e\u0631 \u0646\u0627\u0645\u06a9\u0645\u0644 \u062c\u0648\u0627\u0628 \u06a9\u0648 \u0642\u0628\u0648\u0644 \u06a9\u0631\u0646\u06d2 \u06a9\u06d2 \u0628\u062c\u0627\u0626\u06d2 \u0627\u06cc\u06a9 \u0686\u06be\u0648\u0679\u06d2 \u0648\u0642\u0641\u06d2 \u067e\u0631 \u062f\u0648\u0628\u0627\u0631\u06c1 \u06a9\u0648\u0634\u0634 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4 \u067e\u0631\u0633\u06a9\u0648\u0646 \u0627\u062f\u0648\u0627\u0631 \u06a9\u06d2 \u0644\u06cc\u06d2\u060c \u06cc\u06c1 \u0648\u0646\u0688\u0648 30 \u0645\u0646\u0679 \u062a\u06a9 \u0628\u0691\u06be \u0633\u06a9\u062a\u06cc \u06c1\u06d2\u06d4<\/p>\n<p>\u06c1\u0631 \u0642\u0628\u0648\u0644 \u0634\u062f\u06c1 \u062c\u0648\u0627\u0628 \u06a9\u0648 \u0645\u0639\u0645\u0648\u0644 \u067e\u0631 \u0644\u0627\u0646\u06d2 \u0633\u06d2 \u067e\u06c1\u0644\u06d2 \u0628\u0631\u0627\u06c1 \u0631\u0627\u0633\u062a JSONL \u06a9\u0648 \u0644\u06a9\u06be\u0627 \u062c\u0627\u062a\u0627 \u06c1\u06d2\u06d4 \u0645\u06cc\u0646\u06cc \u0641\u06cc\u0633\u0679 \u0633\u06cc\u0634\u0646 \u06a9\u06cc \u062d\u062f\u0648\u062f\u060c \u0679\u06a9 \u06a9\u0627\u0624\u0646\u0679\u060c \u0679\u0627\u0626\u0645 \u0627\u0633\u0679\u06cc\u0645\u067e\u060c \u0645\u0634\u0627\u06c1\u062f\u06c1 \u0634\u062f\u06c1 \u0641\u06cc\u0644\u0688\u0632 \u0627\u0648\u0631 \u062a\u0644\u0627\u0634 \u06a9\u06d2 \u0627\u0639\u062f\u0627\u062f\u0648\u0634\u0645\u0627\u0631 \u06a9\u06d2 \u0633\u0627\u062a\u06be \u0645\u062d\u0641\u0648\u0638 \u06a9\u06cc\u0627 \u062c\u0627\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<p>\u0627\u0628 \u0645\u06a9\u0645\u0644 AAPL \u0633\u06cc\u0634\u0646 \u062d\u0627\u0635\u0644 \u06a9\u0631\u06cc\u06ba\u06d4<\/p>\n<pre><code class=\"language-python\">from replay.loader import fetch_session\n\nSYMBOL = \"AAPL\"\nDATE = \"2026-07-15\"\n\nprint(\"=== fullday ===\")\n\nmanifest, raw_path = fetch_session(\n    SYMBOL,\n    DATE,\n    tag=\"fullday\"\n)\n\nprint(\n    f\" window {manifest['window_from_utc']}..{manifest['window_to_utc']} | \"\n    f\"{manifest['ticks']:,} ticks, {manifest['pages']} pages, \"\n    f\"{manifest['retries']} retries | \"\n    f\"{manifest['elapsed_s']}s, {manifest['api_calls']} metered api calls\"\n)\n\nprint(\n    f\" first_ts {manifest['first_timestamp_ms']} \"\n    f\"last_ts {manifest['last_timestamp_ms']}\"\n)\n\nprint(\" fields:\", manifest[\"fields\"])\n<\/code><\/pre>\n<p>\u0641\u0627\u0626\u0646\u0644 \u06a9\u0644\u06cc\u0646 \u0627\u067e \u0631\u0646 \u0646\u06d2 \u067e\u06c1\u0644\u06d2 \u0633\u06d2 \u0688\u0627\u0624\u0646 \u0644\u0648\u0688 \u06a9\u0631\u062f\u06c1 \u0633\u06cc\u0634\u0646\u0632 \u06a9\u0648 \u062f\u0648\u0628\u0627\u0631\u06c1 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u06cc\u0627<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/umang.pk\/wp-content\/uploads\/2026\/08\/1787822510_822_\u0645\u0627\u0631\u06a9\u06cc\u0679-\u0679\u0627\u0626\u0645-\u0645\u0634\u06cc\u0646-\u0628\u0646\u0627\u0646\u0627-\u0627\u0632\u06af\u0631-\u0627\u0648\u0631-\u0648\u06cc\u0628-\u0633\u0627\u06a9\u0679-\u06a9\u0627-\u0627\u0633\u062a\u0639\u0645\u0627\u0644.png\" alt=\"eoddh \u062a\u062c\u0627\u0631\u062a\u06cc \u0633\u06cc\u0634\u0646 \u0688\u0627\u0624\u0646 \u0644\u0648\u0688\" style=\"display:block;margin:0 auto\" width=\"600\" height=\"400\" loading=\"lazy\" title=\"\"><\/p>\n<p>\u06c1\u0645 \u0627\u0628 \u06c1\u06cc\u06ba <code>1,032,411<\/code> \u062e\u0627\u0645 \u0644\u06cc\u0646 \u062f\u06cc\u0646 \u06a9\u06d2 \u0631\u06cc\u06a9\u0627\u0631\u0688 \u062c\u0648 \u067e\u0648\u0631\u06d2 \u0631\u06cc\u06af\u0648\u0644\u0631 \u0633\u06cc\u0634\u0646 \u0627\u0648\u0631 \u0631\u0639\u0627\u06cc\u062a\u06cc \u0645\u062f\u062a \u06a9\u0627 \u0627\u062d\u0627\u0637\u06c1 \u06a9\u0631\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4 \u06a9\u06c1 <code>145<\/code> \u0648\u0627\u0626\u0679 \u0644\u0633\u0679 \u0634\u062f\u06c1 \u0635\u0641\u062d\u0627\u062a \u0627\u0648\u0631 <code>16<\/code> \u062f\u0648\u0628\u0627\u0631\u06c1 \u06a9\u0648\u0634\u0634\u06cc\u06ba \u06cc\u06c1 \u0628\u06be\u06cc \u0638\u0627\u06c1\u0631 \u06a9\u0631\u062a\u06cc \u06c1\u06cc\u06ba \u06a9\u06c1 \u0627\u0633 \u0637\u0631\u062d \u06a9\u06d2 \u06af\u06be\u0646\u06d2 \u0679\u06a9 \u0688\u06cc\u0679\u0627 \u06a9\u06d2 \u0644\u06cc\u06d2 \u0627\u06cc\u06a9 \u0645\u0642\u0631\u0631\u06c1 \u062f\u0631\u062e\u0648\u0627\u0633\u062a \u06a9\u06cc \u0645\u062f\u062a \u06a9\u06cc\u0648\u06ba \u06a9\u0645\u0632\u0648\u0631 \u0645\u0641\u0631\u0648\u0636\u06c1 \u062a\u06be\u06cc\u06d4<\/p>\n<p>\u062a\u0627\u06c1\u0645\u060c \u06cc\u06c1 \u0631\u06cc\u06a9\u0627\u0631\u0688 \u0628\u0627\u0644\u06a9\u0644 \u0627\u0633\u06cc \u0637\u0631\u062d \u0645\u062d\u0641\u0648\u0638 \u06a9\u06cc\u06d2 \u062c\u0627\u062a\u06d2 \u06c1\u06cc\u06ba \u062c\u06cc\u0633\u06d2 \u0648\u06c1 EODHD \u0633\u06d2 \u062d\u0627\u0635\u0644 \u06a9\u06cc\u06d2 \u06af\u0626\u06d2 \u062a\u06be\u06d2\u06d4 \u0627\u0633 \u0633\u06d2 \u067e\u06c1\u0644\u06d2 \u06a9\u06c1 \u06a9\u0648\u0626\u06cc \u067e\u0644\u06d2 \u0628\u06cc\u06a9 \u0627\u0646\u062c\u0646 \u0627\u0633\u06d2 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631 \u0633\u06a9\u06d2\u060c \u0627\u0633\u06d2 \u067e\u06c1\u0644\u06d2 \u0648\u0627\u0642\u0639\u0627\u062a \u06a9\u06cc \u0627\u06cc\u06a9 \u062a\u0639\u06cc\u06cc\u0646\u0627\u062a\u06cc \u062f\u0627\u062e\u0644\u06cc \u062a\u0631\u062a\u06cc\u0628 \u0628\u0646\u0646\u0627 \u0686\u0627\u06c1\u06cc\u06d2\u06d4<\/p>\n<h2 id=\"heading-normalize-tick-data-into-a-replay-tape\">\u0679\u06a9 \u0688\u06cc\u0679\u0627 \u06a9\u0648 \u067e\u0644\u06d2 \u0628\u06cc\u06a9 \u0679\u06cc\u067e \u0645\u06cc\u06ba \u0645\u0639\u0645\u0648\u0644 \u0628\u0646\u0627\u0626\u06cc\u06ba<\/h2>\n<p>\u0644\u0648\u0688\u0631 \u067e\u0648\u0631\u06d2 \u0633\u06cc\u0634\u0646 \u0645\u06cc\u06ba \u06a9\u0627\u0645 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u060c \u0644\u06cc\u06a9\u0646 \u067e\u0644\u06d2 \u0628\u06cc\u06a9 \u0627\u0646\u062c\u0646 \u06a9\u0648 \u0628\u0631\u0627\u06c1 \u0631\u0627\u0633\u062a EODHD \u06a9\u06d2 \u062e\u0627\u0645 \u0631\u0633\u067e\u0627\u0646\u0633 \u0641\u0627\u0631\u0645\u06cc\u0679 \u06a9\u06d2 \u0633\u0627\u062a\u06be \u06a9\u0627\u0645 \u0646\u06c1\u06cc\u06ba \u06a9\u0631\u0646\u0627 \u0686\u0627\u06c1\u06cc\u06d2\u06d4 \u0679\u06a9 \u0627\u06cc\u0646\u0688 \u067e\u0648\u0627\u0626\u0646\u0679 \u0627\u06cc\u06a9 \u0645\u062a\u0648\u0627\u0632\u06cc \u0635\u0641 \u0645\u06cc\u06ba \u0679\u0627\u0626\u0645 \u0627\u0633\u0679\u06cc\u0645\u067e\u060c \u0642\u06cc\u0645\u062a\u060c \u0633\u0627\u0626\u0632\u060c \u062a\u0631\u062a\u06cc\u0628 \u0646\u0645\u0628\u0631\u060c \u0627\u0648\u0631 \u0645\u0627\u0631\u06a9\u06cc\u0679 \u06a9\u0648\u0688 \u062c\u06cc\u0633\u06d2 \u0641\u06cc\u0644\u0688\u0632 \u0648\u0627\u067e\u0633 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<p>\u06a9\u06be\u06cc\u0644\u0646\u06d2 \u0633\u06d2 \u067e\u06c1\u0644\u06d2\u060c \u0622\u067e \u06a9\u0648 \u0627\u0633 \u0628\u0627\u062a \u06a9\u0648 \u06cc\u0642\u06cc\u0646\u06cc \u0628\u0646\u0627\u0646\u0627 \u06c1\u0648\u06af\u0627 \u06a9\u06c1 \u0635\u0641 \u06a9\u0648 \u062a\u0631\u062a\u06cc\u0628 \u062f\u06cc\u0627 \u06af\u06cc\u0627 \u06c1\u06d2\u060c \u0648\u0627\u0642\u0639\u0627\u062a \u06a9\u06cc \u0627\u06cc\u06a9 \u062a\u0639\u06cc\u06cc\u0646\u0627\u062a\u06cc \u062a\u0631\u062a\u06cc\u0628 \u0642\u0627\u0626\u0645 \u06a9\u0631\u06cc\u06ba\u060c \u0688\u067e\u0644\u06cc\u06a9\u06cc\u0679\u0633 \u06a9\u0648 \u06c1\u0679\u0627 \u062f\u06cc\u06ba\u060c \u0627\u0648\u0631 \u0646\u062a\u0627\u0626\u062c \u06a9\u0648 \u0627\u06cc\u06a9 \u062f\u0627\u062e\u0644\u06cc \u0634\u06a9\u0644 \u0645\u06cc\u06ba \u062a\u0628\u062f\u06cc\u0644 \u06a9\u0631\u06cc\u06ba\u06d4<\/p>\n<p>\u0645\u0646\u0637\u0642 \u0645\u0646\u062f\u0631\u062c\u06c1 \u0630\u06cc\u0644 \u06c1\u06d2: <code>replay\/events.py<\/code>:<\/p>\n<pre><code class=\"language-plaintext\">market-time-machine\/\n\u2514\u2500\u2500 replay\/\n    \u251c\u2500\u2500 config.py\n    \u251c\u2500\u2500 loader.py\n    \u2514\u2500\u2500 events.py\n<\/code><\/pre>\n<p>\u06c1\u0645 \u06cc\u06c1\u0627\u06ba \u062f\u0648 \u0627\u0634\u06cc\u0627\u0621 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631\u06cc\u06ba \u06af\u06d2\u06d4 <code>TradeEvent<\/code> \u0628\u0627\u0644\u0622\u062e\u0631\u060c \u06cc\u06c1 \u0648\u06cc\u0628 \u0633\u0627\u06a9\u0679 \u067e\u0631 \u0645\u0646\u062a\u0642\u0644 \u06c1\u0648\u0646\u06d2 \u06a9\u06cc \u0635\u0648\u0631\u062a \u0645\u06cc\u06ba \u0627\u06cc\u06a9 \u06c1\u06cc \u0644\u06cc\u0646 \u062f\u06cc\u0646 \u06a9\u06cc \u0646\u0645\u0627\u0626\u0646\u062f\u06af\u06cc \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4 <code>TradeTape<\/code> \u06a9\u0627\u0644\u0645\u06cc NumPy \u0635\u0641\u0648\u06ba \u0645\u06cc\u06ba \u067e\u0648\u0631\u06d2 \u0633\u06cc\u0634\u0646\u0632 \u06a9\u0648 \u0645\u0624\u062b\u0631 \u0637\u0631\u06cc\u0642\u06d2 \u0633\u06d2 \u0627\u0633\u0679\u0648\u0631 \u06a9\u0631\u062a\u0627 \u06c1\u06d2 \u0627\u0648\u0631 \u0627\u0646\u0641\u0631\u0627\u062f\u06cc \u0633\u06cc\u0634\u0646\u0632 \u06a9\u0648 \u0639\u0645\u0644\u06cc \u0634\u06a9\u0644 \u062f\u06cc\u062a\u0627 \u06c1\u06d2\u06d4 <code>TradeEvent<\/code> \u0636\u0631\u0648\u0631\u062a \u06a9\u06d2 \u0648\u0642\u062a \u06c1\u06cc \u0627\u0634\u06cc\u0627\u0621 \u0628\u0646\u0627\u0626\u06cc\u06ba\u06d4<\/p>\n<h3 id=\"heading-create-replayeventspy\">\u0628\u0646\u0627\u0646\u0627 <code>replay\/events.py<\/code><\/h3>\n<p>\u0628\u0646\u0627\u0646\u0627 <code>replay\/events.py<\/code> \u06a9\u06d2 \u0633\u0627\u062a\u06be:<\/p>\n<pre><code class=\"language-python\">from dataclasses import dataclass\nimport numpy as np\n\nfrom . import config\nfrom .loader import read_pages\n\n@dataclass(frozen=True)\nclass TradeEvent:\n    symbol: str\n    timestamp_ms: int\n    price: float\n    size: int\n    sequence: int\n    market: str\n    sub_market: str\n    sale_condition: str\n    source: str = \"replay\"\n\n    def to_wire(self):\n        sl = self.sale_condition\n\n        return {\n            \"type\": \"trade\",\n            \"symbol\": self.symbol,\n            \"timestamp_ms\": self.timestamp_ms,\n            \"price\": self.price,\n            \"size\": self.size,\n            \"sequence\": self.sequence,\n            \"source\": self.source,\n            \"metadata\": {\n                \"market\": self.market,\n                \"sub_market\": self.sub_market or None,\n                \"sale_condition\": sl,\n                \"odd_lot\": \"I\" in sl,\n                \"zero_size\": self.size == 0,\n                \"last_sale_eligible\": not (\n                    set(sl) & config.NON_LAST_SALE\n                )\n            }\n        }\n\n\nclass TradeTape:\n    def __init__(self, symbol, ts, price, size, seq, mkt, sub, sl):\n        self.symbol = symbol\n        self.ts = ts\n        self.price = price\n        self.size = size\n        self.seq = seq\n        self.mkt = mkt\n        self.sub = sub\n        self.sl = sl\n\n    def __len__(self):\n        return len(self.ts)\n\n    def __getitem__(self, i):\n        return TradeEvent(\n            self.symbol,\n            int(self.ts[i]),\n            float(self.price[i]),\n            int(self.size[i]),\n            int(self.seq[i]),\n            str(self.mkt[i]),\n            str(self.sub[i]),\n            str(self.sl[i])\n        )\n\n    def index_at(self, ts_ms):\n        return int(np.searchsorted(self.ts, ts_ms, side=\"left\"))\n\n    def span(self):\n        if not len(self):\n            return None, None\n\n        return int(self.ts[0]), int(self.ts[-1])\n\n    def save(self, path):\n        np.savez_compressed(\n            path,\n            ts=self.ts,\n            price=self.price,\n            size=self.size,\n            seq=self.seq,\n            mkt=self.mkt,\n            sub=self.sub,\n            sl=self.sl,\n            symbol=np.array([self.symbol])\n        )\n\n    @classmethod\n    def load(cls, path):\n        z = np.load(path, allow_pickle=False)\n\n        return cls(\n            str(z[\"symbol\"][0]),\n            z[\"ts\"],\n            z[\"price\"],\n            z[\"size\"],\n            z[\"seq\"],\n            z[\"mkt\"],\n            z[\"sub\"],\n            z[\"sl\"]\n        )\n\n\ndef normalize(raw_path, symbol, verbose=True):\n    cols = {k: [] for k in config.FIELDS}\n    pages = 0\n\n    for page in read_pages(raw_path):\n        pages += 1\n        p = page[\"payload\"]\n\n        lens = {k: len(p.get(k, [])) for k in config.FIELDS}\n\n        if len(set(lens.values())) != 1:\n            raise ValueError(\n                f\"ragged page {page['from']}: {lens}\"\n            )\n\n        for k in config.FIELDS:\n            cols[k].extend(p[k])\n\n    ts = np.asarray(cols[\"ts\"], dtype=np.int64)\n    price = np.asarray(cols[\"price\"], dtype=np.float64)\n    size = np.asarray(cols[\"shares\"], dtype=np.int64)\n    seq = np.asarray(cols[\"seq\"], dtype=np.int64)\n    mkt = np.asarray(cols[\"mkt\"], dtype=str)\n    sub = np.asarray(cols[\"sub_mkt\"], dtype=str)\n    sl = np.asarray(cols[\"sl\"], dtype=str)\n\n    raw_n = len(ts)\n\n    def arrays(mask):\n        return tuple(\n            a[mask]\n            for a in (ts, price, size, seq, mkt, sub, sl)\n        )\n\n    keep = (\n        (ts > 0)\n        & np.isfinite(price)\n        & (price > 0)\n        & (size >= 0)\n    )\n\n    ts, price, size, seq, mkt, sub, sl = arrays(keep)\n\n    order = np.lexsort((seq, ts))\n    ts, price, size, seq, mkt, sub, sl = arrays(order)\n\n    dup = np.zeros(len(ts), dtype=bool)\n\n    if len(ts) > 1:\n        dup[1:] = (\n            (ts[1:] == ts[:-1])\n            & (seq[1:] == seq[:-1])\n        )\n\n    ts, price, size, seq, mkt, sub, sl = arrays(~dup)\n\n    tape = TradeTape(\n        symbol,\n        ts,\n        price,\n        size,\n        seq,\n        mkt,\n        sub,\n        sl\n    )\n\n    odd = sum(\"I\" in str(s) for s in sl)\n    elig = sum(\n        not (set(str(s)) & config.NON_LAST_SALE)\n        for s in sl\n    )\n\n    rep = {\n        \"pages\": pages,\n        \"raw\": raw_n,\n        \"kept\": len(ts),\n        \"dropped\": raw_n - len(ts) - int(dup.sum()),\n        \"dupes\": int(dup.sum()),\n        \"zero_size\": int((size == 0).sum()),\n        \"odd_lot\": int(odd),\n        \"last_sale_eligible\": int(elig),\n        \"seq_strict\": bool(\n            np.all(seq[1:] > seq[:-1])\n        ) if len(seq) > 1 else True,\n        \"span\": tape.span()\n    }\n\n    if verbose:\n        n = max(1, len(ts))\n\n        print(\n            f\"{rep['raw']:,} raw -> {rep['kept']:,} kept \"\n            f\"({rep['dupes']} dupes, {rep['dropped']} invalid)\"\n        )\n\n        print(\n            f\"zero-size {100*rep['zero_size']\/n:.1f}% | \"\n            f\"odd-lot {100*odd\/n:.1f}% | \"\n            f\"last-sale-eligible {100*elig\/n:.1f}%\"\n        )\n\n        print(\n            f\"seq strictly increasing: {rep['seq_strict']}\"\n        )\n\n    return tape, rep\n<\/code><\/pre>\n<p>\u067e\u06c1\u0644\u06cc \u062a\u0648\u062b\u06cc\u0642 \u0679\u0631\u0627\u0646\u0632\u06cc\u06a9\u0634\u0646 \u06a9\u06cc \u062a\u0634\u06a9\u06cc\u0644 \u0633\u06d2 \u067e\u06c1\u0644\u06d2 \u06c1\u0648\u062a\u06cc \u06c1\u06d2\u06d4 \u0633\u0648\u0631\u0633 \u0641\u06cc\u0644\u0688\u0632 \u0645\u062a\u0648\u0627\u0632\u06cc \u0635\u0641\u0648\u06ba \u0645\u06cc\u06ba \u0622\u062a\u06d2 \u06c1\u06cc\u06ba\u060c \u0644\u06c1\u0630\u0627 \u0635\u0641\u062d\u06c1 \u067e\u0631 \u0645\u0648\u062c\u0648\u062f \u062a\u0645\u0627\u0645 \u0641\u06cc\u0644\u0688\u0632 \u0645\u06cc\u06ba \u0645\u0634\u0627\u06c1\u062f\u0627\u062a \u06a9\u06cc \u0627\u06cc\u06a9 \u06c1\u06cc \u062a\u0639\u062f\u0627\u062f \u06c1\u0648\u0646\u06cc \u0686\u0627\u06c1\u06cc\u06d2\u06d4 \u0628\u0635\u0648\u0631\u062a \u062f\u06cc\u06af\u0631\u060c \u0627\u0646 \u06a9\u0648 \u06cc\u06a9\u062c\u0627 \u06a9\u0631\u0646\u06d2 \u0633\u06d2 \u0627\u06cc\u06a9 \u0679\u0631\u0627\u0646\u0632\u06cc\u06a9\u0634\u0646 \u06a9\u06cc \u0642\u06cc\u0645\u062a \u062e\u0648\u062f \u0628\u062e\u0648\u062f \u062f\u0648\u0633\u0631\u06d2 \u0679\u0631\u0627\u0646\u0632\u06cc\u06a9\u0634\u0646 \u06a9\u06d2 \u0679\u0627\u0626\u0645 \u0627\u0633\u0679\u06cc\u0645\u067e \u06a9\u06d2 \u0633\u0627\u062a\u06be \u0645\u0646\u0633\u0644\u06a9 \u06c1\u0648 \u0633\u06a9\u062a\u06cc \u06c1\u06d2\u06d4<\/p>\n<p>\u0627\u0633 \u06a9\u06d2 \u0628\u0639\u062f\u060c \u0635\u0641 \u06a9\u0648 NumPy \u0645\u06cc\u06ba \u062a\u0628\u062f\u06cc\u0644 \u06a9\u0631 \u062f\u06cc\u0627 \u062c\u0627\u062a\u0627 \u06c1\u06d2\u060c \u0628\u0646\u06cc\u0627\u062f\u06cc \u063a\u0644\u0637 \u0631\u06cc\u06a9\u0627\u0631\u0688\u0632 \u06a9\u0648 \u06c1\u0679\u0627 \u062f\u06cc\u0627 \u062c\u0627\u062a\u0627 \u06c1\u06d2\u060c \u0627\u0648\u0631 \u0644\u06cc\u0646 \u062f\u06cc\u0646 \u06a9\u0648 \u0627\u0633 \u0637\u0631\u062d \u062a\u0631\u062a\u06cc\u0628 \u062f\u06cc\u0627 \u062c\u0627\u062a\u0627 \u06c1\u06d2: <code>(timestamp, sequence)<\/code>. \u0679\u0627\u0626\u0645 \u0627\u0633\u0679\u06cc\u0645\u067e \u062a\u0627\u0631\u06cc\u062e \u06a9\u06cc \u062a\u0631\u062a\u06cc\u0628 \u0641\u0631\u0627\u06c1\u0645 \u06a9\u0631\u062a\u06d2 \u06c1\u06cc\u06ba\u060c \u062c\u0628 \u06a9\u06c1 \u062a\u0631\u062a\u06cc\u0628 \u0646\u0645\u0628\u0631 \u062c\u0628 \u0627\u06cc\u06a9 \u0633\u06d2 \u0632\u06cc\u0627\u062f\u06c1 \u0644\u06cc\u0646 \u062f\u06cc\u0646 \u0627\u06cc\u06a9 \u06c1\u06cc \u0645\u0644\u06cc \u0633\u06cc\u06a9\u0646\u0688 \u06a9\u0627 \u0627\u0634\u062a\u0631\u0627\u06a9 \u06a9\u0631\u062a\u06d2 \u06c1\u06cc\u06ba \u062a\u0648 \u062a\u0639\u06cc\u06cc\u0646\u0627\u062a\u06cc \u062a\u0631\u062a\u06cc\u0628 \u0641\u0631\u0627\u06c1\u0645 \u06a9\u0631\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4<\/p>\n<p>\u0627\u06cc\u06a9 \u06c1\u06cc \u0679\u0627\u0626\u0645 \u0627\u0633\u0679\u06cc\u0645\u067e \u0627\u0648\u0631 \u062a\u0631\u062a\u06cc\u0628 \u06a9\u06d2 \u0633\u0627\u062a\u06be \u0635\u062d\u06cc\u062d \u0688\u067e\u0644\u06cc\u06a9\u06cc\u0679\u0633 \u06a9\u0648 \u067e\u06be\u0631 \u06c1\u0679\u0627 \u062f\u06cc\u0627 \u062c\u0627\u062a\u0627 \u06c1\u06d2\u06d4 <code>TradeTape<\/code> \u0627\u06cc\u06a9 \u0645\u0644\u06cc\u0646 \u0633\u06d2 \u0632\u06cc\u0627\u062f\u06c1 \u0645\u0633\u062a\u0642\u0644 \u067e\u0627\u0626\u062a\u06be\u0648\u0646 \u0627\u0634\u06cc\u0627\u0621 \u0645\u062e\u062a\u0635 \u06a9\u0631\u0646\u06d2 \u06a9\u06d2 \u0628\u062c\u0627\u0626\u06d2\u060c \u0645\u06cc\u06ba \u0646\u062a\u06cc\u062c\u06d2 \u0645\u06cc\u06ba \u0622\u0646\u06d2 \u0648\u0627\u0644\u06d2 \u06a9\u0627\u0644\u0645\u0648\u06ba \u06a9\u0648 \u0635\u0641\u0648\u06ba \u06a9\u06d2 \u0637\u0648\u0631 \u067e\u0631 \u0631\u06a9\u06be\u062a\u0627 \u06c1\u0648\u06ba\u060c \u062c\u0648 \u0645\u06cc\u0631\u06d2 \u0633\u06cc\u0634\u0646\u0632 \u06a9\u0648 \u062f\u0646 \u0628\u06be\u0631 \u0645\u06cc\u0645\u0648\u0631\u06cc \u067e\u0631 \u06a9\u0627\u0641\u06cc \u062d\u062f \u062a\u06a9 \u06c1\u0644\u06a9\u0627 \u0631\u06a9\u06be\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<p>\u0627\u0628 \u062e\u0627\u0645 \u0633\u06cc\u0634\u0646 \u06a9\u0648 \u0645\u0639\u0645\u0648\u0644 \u067e\u0631 \u0644\u0627\u0626\u06cc\u06ba \u0627\u0648\u0631 \u0627\u0633\u06d2 \u0646\u06cc\u0686\u06d2 \u0645\u062d\u0641\u0648\u0638 \u06a9\u0631\u06cc\u06ba\u06d4 <code>data\/processed\/<\/code>:<\/p>\n<pre><code class=\"language-python\">import json\n\nfrom replay import config\nfrom replay.events import normalize\n\ntape, report = normalize(raw_path, SYMBOL)\n\ntape.save(\n    config.PROCESSED \/ f\"{SYMBOL}_{DATE}_fullday.npz\"\n)\n\nlo, hi = tape.span()\n\nprint(\n    f\"span {lo}..{hi} \"\n    f\"({(hi-lo)\/3_600_000:.2f} market hours)\"\n)\n\nprint(\"first 3 normalized events:\")\n\nfor i in range(3):\n    print(json.dumps(tape[i].to_wire()))\n<\/code><\/pre>\n<p>\u0627\u0635\u0644 \u0646\u0627\u0631\u0645\u0644\u0627\u0626\u0632\u06cc\u0634\u0646 \u0631\u0646 \u0645\u0646\u062f\u0631\u062c\u06c1 \u0630\u06cc\u0644 \u06c1\u06d2:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/umang.pk\/wp-content\/uploads\/2026\/08\/1787822510_375_\u0645\u0627\u0631\u06a9\u06cc\u0679-\u0679\u0627\u0626\u0645-\u0645\u0634\u06cc\u0646-\u0628\u0646\u0627\u0646\u0627-\u0627\u0632\u06af\u0631-\u0627\u0648\u0631-\u0648\u06cc\u0628-\u0633\u0627\u06a9\u0679-\u06a9\u0627-\u0627\u0633\u062a\u0639\u0645\u0627\u0644.png\" alt=\"\u0645\u0639\u0645\u0648\u0644 \u06a9\u06d2 \u0645\u0637\u0627\u0628\u0642 \u0648\u0627\u0642\u0639\u06c1 \u067e\u0631 \u0639\u0645\u0644 \u062f\u0631\u0622\u0645\u062f\" style=\"display:block;margin:0 auto\" width=\"600\" height=\"400\" loading=\"lazy\" title=\"\"><\/p>\n<p>\u0627\u06cc\u06a9 \u0645\u0644\u06cc\u0646 \u0633\u06d2 \u0632\u06cc\u0627\u062f\u06c1 \u062e\u0627\u0645 \u0645\u0634\u0627\u06c1\u062f\u0627\u062a\u060c \u0635\u0631\u0641 \u062f\u0648 \u0688\u067e\u0644\u06cc\u06a9\u06cc\u0679 \u0631\u06cc\u06a9\u0627\u0631\u0688\u0632 \u06a9\u06be\u0648 \u06af\u0626\u06d2 \u06c1\u06cc\u06ba\u060c \u0627\u0648\u0631 \u06a9\u0648\u0626\u06cc \u0628\u06be\u06cc \u0631\u06cc\u06a9\u0627\u0631\u0688 \u0688\u06cc\u0641\u0627\u0644\u0679 \u0679\u0627\u0626\u0645 \u0627\u0633\u0679\u06cc\u0645\u067e\u060c \u0642\u06cc\u0645\u062a\u060c \u06cc\u0627 \u0633\u0627\u0626\u0632 \u06a9\u06cc \u062c\u0627\u0646\u0686 \u0645\u06cc\u06ba \u0646\u0627\u06a9\u0627\u0645 \u0646\u06c1\u06cc\u06ba \u06c1\u0648\u062a\u0627 \u06c1\u06d2\u06d4 \u0631\u06cc \u067e\u0644\u06d2 \u06a9\u06d2 \u0644\u06cc\u06d2\u060c \u062c\u0648 \u0686\u06cc\u0632 \u0632\u06cc\u0627\u062f\u06c1 \u0627\u06c1\u0645 \u06c1\u06d2 \u0648\u06c1 \u06cc\u06c1 \u06c1\u06d2 \u06a9\u06c1 \u0645\u0639\u0645\u0648\u0644 \u06a9\u06d2 \u0645\u0637\u0627\u0628\u0642 \u062a\u0631\u062a\u06cc\u0628 \u06a9\u0648 \u0633\u062e\u062a\u06cc \u0633\u06d2 \u0628\u0691\u06be\u0627\u06cc\u0627 \u06af\u06cc\u0627 \u06c1\u06d2\u06d4<\/p>\n<h3 id=\"heading-create-a-smaller-tape-for-benchmarks-and-tests\">\u0628\u06cc\u0646\u0686 \u0645\u0627\u0631\u06a9\u0646\u06af \u0627\u0648\u0631 \u062c\u0627\u0646\u0686 \u06a9\u06d2 \u0644\u06cc\u06d2 \u0686\u06be\u0648\u0679\u06d2 \u0679\u06cc\u067e \u0628\u0646\u0627\u0626\u06cc\u06ba<\/h3>\n<p>\u0633\u0627\u0631\u0627 \u062f\u0646\u060c \u0679\u06cc\u067e \u0622\u067e \u06a9\u06d2 \u0622\u062e\u0631\u06cc \u067e\u0644\u06d2 \u0628\u06cc\u06a9 \u06a9\u0648 \u0637\u0627\u0642\u062a \u062f\u06d2 \u06af\u06cc\u06d4 \u062a\u0627\u06c1\u0645\u060c \u0679\u0627\u0626\u0645\u0646\u06af \u0628\u06cc\u0646\u0686 \u0645\u0627\u0631\u06a9\u0633 \u0627\u0648\u0631 \u062e\u0648\u062f\u06a9\u0627\u0631 \u0679\u06cc\u0633\u0679\u0648\u06ba \u06a9\u06d2 \u0644\u06cc\u06d2\u060c \u0622\u067e \u06a9\u0648 \u06c1\u0631 \u0628\u0627\u0631 \u067e\u0648\u0631\u06d2 6.5 \u06af\u06be\u0646\u0679\u06d2 \u0686\u0644\u0627\u0646\u06d2 \u06a9\u06cc \u0636\u0631\u0648\u0631\u062a \u0646\u06c1\u06cc\u06ba \u06c1\u06d2\u06d4<\/p>\n<p>\u0622\u0626\u06cc\u06d2 12:00 AM \u0633\u06d2 12:15 AM \u062a\u06a9 15 \u0645\u0646\u0679 \u06a9\u0627 \u0679\u06a9\u0691\u0627 \u0628\u0631\u0627\u06c1 \u0631\u0627\u0633\u062a \u0627\u06cc\u06a9 \u0639\u0627\u0645 \u067e\u0648\u0631\u06d2 \u062f\u0646 \u06a9\u06d2 \u0679\u06cc\u067e \u0633\u06d2 \u0646\u06a9\u0627\u0644\u06cc\u06ba\u06d4<\/p>\n<pre><code class=\"language-python\">from datetime import datetime\nfrom zoneinfo import ZoneInfo\n\nfrom replay.events import TradeTape\n\ntz = ZoneInfo(config.MARKET_TZ)\n\nquiet_start = int(\n    datetime(\n        2026, 7, 15, 12, 0,\n        tzinfo=tz\n    ).timestamp() * 1000\n)\n\nquiet_end = quiet_start + 15 * 60_000\n\ni = tape.index_at(quiet_start)\nj = tape.index_at(quiet_end)\n\nquiet_tape = TradeTape(\n    tape.symbol,\n    tape.ts[i:j],\n    tape.price[i:j],\n    tape.size[i:j],\n    tape.seq[i:j],\n    tape.mkt[i:j],\n    tape.sub[i:j],\n    tape.sl[i:j]\n)\n\nquiet_tape.save(config.PROCESSED \/ f\"{SYMBOL}_{DATE}_quiet15m.npz\")\n<\/code><\/pre>\n<p>\u0627\u0628 \u0622\u067e \u06a9\u06d2 \u067e\u0627\u0633 \u062f\u0648 \u067e\u0631\u0648\u0633\u06cc\u0633 \u0634\u062f\u06c1 \u0679\u06cc\u067e \u06c1\u06cc\u06ba\u06d4 \u0627\u06cc\u06a9 \u0627\u06cc\u0646\u0688 \u0679\u0648 \u0627\u06cc\u0646\u0688 \u0631\u06cc \u067e\u0644\u06d2 \u06a9\u06d2 \u0644\u06cc\u06d2 \u0627\u06cc\u06a9 \u0645\u06a9\u0645\u0644 \u0633\u06cc\u0634\u0646 \u06c1\u06d2\u060c \u0627\u0648\u0631 \u062f\u0648\u0633\u0631\u0627 \u0631\u06cc\u067e\u0628\u0644 \u0627\u06cc\u0628\u0644 \u0679\u0627\u0626\u0645\u0646\u06af \u0627\u0648\u0631 \u06a9\u0646\u0679\u0631\u0648\u0644 \u0679\u06cc\u0633\u0679\u0646\u06af \u06a9\u06d2 \u0644\u06cc\u06d2 \u062d\u0642\u06cc\u0642\u06cc \u062f\u0646\u06cc\u0627 \u06a9\u06cc \u0645\u0627\u0631\u06a9\u06cc\u0679 \u06a9\u0627 \u0686\u06be\u0648\u0679\u0627 \u0648\u0642\u0641\u06c1 \u06c1\u06d2\u06d4<\/p>\n<h2 id=\"heading-build-the-historical-replay-clock\">\u0627\u06cc\u06a9 \u0631\u06cc\u06a9\u0627\u0631\u0688 \u067e\u0644\u06d2 \u0628\u06cc\u06a9 \u06af\u06be\u0691\u06cc \u0628\u0646\u0627\u0646\u0627<\/h2>\n<p>\u0627\u0628 \u06c1\u0645\u0627\u0631\u06d2 \u067e\u0627\u0633 \u0627\u06cc\u06a9 \u062a\u0639\u06cc\u06cc\u0646\u0627\u062a\u06cc \u062a\u062c\u0627\u0631\u062a\u06cc \u062a\u0631\u062a\u06cc\u0628 \u06c1\u06d2\u060c \u0644\u06cc\u06a9\u0646 \u0627\u0628 \u0628\u06be\u06cc \u0627\u06cc\u0633\u0627 \u06a9\u0686\u06be \u0646\u06c1\u06cc\u06ba \u06c1\u06d2 \u062c\u0648 \u0627\u0646 \u062a\u062c\u0627\u0631\u062a\u0648\u06ba \u06a9\u0648 \u0628\u0627\u0632\u0627\u0631 \u06a9\u06d2 \u0628\u06c1\u0627\u0624 \u06a9\u06cc \u0637\u0631\u062d \u0628\u0631\u062a\u0627\u0624 \u06a9\u0631\u06d2\u06d4 \u0628\u0633 \u0679\u06cc\u067e \u06a9\u0648 \u0644\u0648\u067e \u06a9\u0631\u06cc\u06ba \u0627\u0648\u0631 Python \u0633\u06cc\u0634\u0646 \u06a9\u0648 \u0627\u062a\u0646\u06cc \u06c1\u06cc \u062a\u06cc\u0632\u06cc \u0633\u06d2 \u067e\u0631\u0648\u0633\u06cc\u0633 \u06a9\u0631\u06d2 \u06af\u0627 \u062c\u062a\u0646\u06cc \u0622\u067e \u06a9\u0627 \u0633\u0633\u0679\u0645 \u0627\u062c\u0627\u0632\u062a \u062f\u06cc\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<p>\u0631\u06cc \u067e\u0644\u06d2 \u06a9\u0644\u0627\u06a9 \u062a\u0627\u0631\u06cc\u062e\u06cc \u0628\u0627\u0632\u0627\u0631 \u06a9\u06d2 \u0627\u0648\u0642\u0627\u062a \u06a9\u0648 \u062f\u06cc\u0648\u0627\u0631 \u06a9\u06cc \u06af\u06be\u0691\u06cc \u06a9\u06d2 \u062d\u0642\u06cc\u0642\u06cc \u0627\u0648\u0642\u0627\u062a \u0645\u06cc\u06ba \u0646\u0642\u0634\u06c1 \u0628\u0646\u0627 \u06a9\u0631 \u0627\u0633 \u0645\u0633\u0626\u0644\u06d2 \u06a9\u0648 \u062d\u0644 \u06a9\u0631\u062a\u06cc \u06c1\u06cc\u06ba\u06d4 \u0622\u067e \u0627\u0635\u0644 \u0679\u0627\u0626\u0645 \u0627\u0633\u0679\u06cc\u0645\u067e \u06a9\u0648 \u062a\u0628\u062f\u06cc\u0644 \u06a9\u06cc\u06d2 \u0628\u063a\u06cc\u0631 \u067e\u0644\u06d2 \u0628\u06cc\u06a9 \u06a9\u06cc \u0631\u0641\u062a\u0627\u0631 \u0628\u06be\u06cc \u062a\u0628\u062f\u06cc\u0644 \u06a9\u0631 \u0633\u06a9\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4<\/p>\n<p>\u0633\u0627\u062f\u06c1 \u0648\u0631\u0698\u0646 \u062a\u0645\u0627\u0645 \u062a\u062c\u0627\u0631\u062a\u06cc \u062c\u0648\u0691\u0648\u06ba \u06a9\u06d2 \u062f\u0631\u0645\u06cc\u0627\u0646 \u062a\u0627\u0631\u06cc\u062e\u06cc \u062e\u0644\u0627 \u067e\u0631 \u0633\u0648 \u0633\u06a9\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<pre><code class=\"language-python\">gap = (next_ts - current_ts) \/ 1000\nawait asyncio.sleep(gap \/ speed)\n<\/code><\/pre>\n<p>\u06a9\u0648 <code>10x<\/code>500ms \u06a9\u0627 \u062a\u0627\u0631\u06cc\u062e\u06cc \u0648\u0642\u0641\u06c1 50ms \u06c1\u0648\u06af\u0627\u06d4 \u06a9\u0648 <code>100x<\/code>\u06cc\u06c1 5ms \u06c1\u0648 \u06af\u0627\u06d4<\/p>\n<p>\u0645\u0633\u0626\u0644\u06c1 \u06cc\u06c1 \u06c1\u06d2\u06d4 <code>asyncio.sleep()<\/code> \u06cc\u06c1 \u0635\u0631\u0641 \u0627\u0633 \u0628\u0627\u062a \u06a9\u06cc \u0636\u0645\u0627\u0646\u062a \u062f\u06cc\u062a\u0627 \u06c1\u06d2 \u06a9\u06c1 \u067e\u06be\u0627\u0646\u0633\u06cc \u062f\u0648\u0628\u0627\u0631\u06c1 \u0634\u0631\u0648\u0639 \u06c1\u0648 \u062c\u0627\u0626\u06d2 \u06af\u06cc\u06d4 <strong>~ \u0628\u0639\u062f<\/strong> \u062a\u0627\u062e\u06cc\u0631 \u06a9\u06cc \u062f\u0631\u062e\u0648\u0627\u0633\u062a \u06a9\u06cc\u06d4 \u0627\u06af\u0631 \u06c1\u0631 \u0646\u06cc\u0646\u062f \u06a9\u06d2 \u0628\u0639\u062f \u062a\u06be\u0648\u0691\u06cc \u062f\u06cc\u0631 \u0628\u0639\u062f \u0628\u06cc\u062f\u0627\u0631\u06cc \u06c1\u0648\u062a\u06cc \u06c1\u06d2\u060c \u0627\u0648\u0631 \u0627\u06af\u0644\u06cc \u062a\u0627\u062e\u06cc\u0631 \u06a9\u0648 \u062f\u06cc\u0631 \u0633\u06d2 \u0628\u06cc\u062f\u0627\u0631\u06cc \u06a9\u06d2 \u0648\u0642\u062a \u0633\u06d2 \u0645\u0627\u067e\u0627 \u062c\u0627\u062a\u0627 \u06c1\u06d2\u060c \u062a\u0648 \u06cc\u06c1 \u062e\u0631\u0627\u0628\u06cc\u0627\u06ba \u0637\u0648\u06cc\u0644 \u067e\u0644\u06d2 \u0628\u06cc\u06a9\u0633 \u0645\u06cc\u06ba \u062c\u0645\u0639 \u06c1\u0648 \u0633\u06a9\u062a\u06cc \u06c1\u06cc\u06ba\u06d4<\/p>\n<p>\u0627\u0633 \u06a9\u06d2 \u0628\u062c\u0627\u0626\u06d2\u060c \u0645\u06cc\u06ba \u06cc\u06c1\u0627\u06ba \u0645\u06a9\u0645\u0644 \u0631\u06cc \u067e\u0644\u06d2 \u067e\u0646 \u06a9\u0631\u0648\u06ba \u06af\u0627: <code>time.monotonic()<\/code>:<\/p>\n<pre><code class=\"language-plaintext\">historical elapsed time\n        \u00f7\nreplay speed\n        +\nwall-clock start\n        =\ntarget wall-clock time\n<\/code><\/pre>\n<p>\u0627\u0633 \u0644\u06cc\u06d2\u060c \u062a\u0645\u0627\u0645 \u062a\u0642\u0631\u06cc\u0628\u0627\u062a \u0627\u06cc\u06a9 \u06c1\u06cc \u0627\u06cc\u0646\u06a9\u0631 \u06a9\u06cc \u0628\u0646\u06cc\u0627\u062f \u067e\u0631 \u0637\u06d2 \u06a9\u06cc \u062c\u0627\u062a\u06cc \u06c1\u06cc\u06ba \u0628\u062c\u0627\u0626\u06d2 \u0627\u0633 \u06a9\u06d2 \u06a9\u06c1 \u067e\u0686\u06be\u0644\u0627 \u0627\u06cc\u0648\u0646\u0679 \u0645\u06a9\u0645\u0644 \u06c1\u0648\u0646\u06d2 \u067e\u0631\u06d4<\/p>\n<h3 id=\"heading-create-replayclockpy\">\u0628\u0646\u0627\u0646\u0627 <code>replay\/clock.py<\/code><\/h3>\n<p>\u0627\u067e\u0646\u06d2 \u067e\u0644\u06d2 \u0628\u06cc\u06a9 \u067e\u06cc\u06a9\u06cc\u062c \u0645\u06cc\u06ba \u06af\u06be\u0691\u06cc \u0634\u0627\u0645\u0644 \u06a9\u0631\u06cc\u06ba\u06d4<\/p>\n<pre><code class=\"language-plaintext\">market-time-machine\/\n\u2514\u2500\u2500 replay\/\n    \u251c\u2500\u2500 config.py\n    \u251c\u2500\u2500 loader.py\n    \u251c\u2500\u2500 events.py\n    \u2514\u2500\u2500 clock.py\n<\/code><\/pre>\n<p>\u0628\u0646\u0627\u0646\u0627 <code>replay\/clock.py<\/code>:<\/p>\n<pre><code class=\"language-python\">import asyncio, time\nimport numpy as np\n\nMIN_SLEEP_S = 0.0005\n\nclass ReplayClock:\n    def __init__(self, start_ms, speed=1.0):\n        self.speed = float(speed)\n        self._anchor_ms = float(start_ms)\n        self._anchor_wall = None\n        self.running = False\n        self.epoch = 0\n\n    def start(self):\n        self._anchor_wall = time.monotonic()\n        self.running = True\n        return self\n\n    def now_ms(self, now=None):\n        if not self.running or self._anchor_wall is None:\n            return self._anchor_ms\n\n        now = now if now is not None else time.monotonic()\n\n        return (\n            self._anchor_ms\n            + (now - self._anchor_wall) * 1000 * self.speed\n        )\n\n    def wall_for(self, ms):\n        return (\n            self._anchor_wall\n            + (ms - self._anchor_ms) \/ 1000 \/ self.speed\n        )\n\n    def _reanchor(self, ms):\n        self._anchor_ms = float(ms)\n        self._anchor_wall = time.monotonic()\n        self.epoch += 1\n\n    def set_speed(self, speed):\n        self._reanchor(self.now_ms())\n        self.speed = float(speed)\n\n    def pause(self):\n        if self.running:\n            self._anchor_ms = self.now_ms()\n            self.running = False\n\n    def resume(self):\n        if not self.running:\n            self._anchor_wall = time.monotonic()\n            self.running = True\n            self.epoch += 1\n\n    def seek(self, ms):\n        self._reanchor(ms)\n\n\ndef new_stats(speed):\n    return {\n        \"emitted\": 0,\n        \"batches\": 0,\n        \"lateness\": [],\n        \"dropped\": 0,\n        \"speed\": speed,\n        \"wall0\": None,\n        \"market0\": None,\n        \"market1\": None\n    }\n\n\ndef summarize(st):\n    if not st[\"lateness\"]:\n        return {\n            \"emitted\": st[\"emitted\"],\n            \"batches\": st[\"batches\"]\n        }\n\n    a = np.asarray(st[\"lateness\"])\n\n    wall = (\n        time.monotonic() - st[\"wall0\"]\n        if st[\"wall0\"] else 0.0\n    )\n\n    mkt = (\n        (st[\"market1\"] - st[\"market0\"]) \/ 1000\n        if st[\"market0\"] is not None else 0.0\n    )\n\n    ok = st[\"dropped\"] == 0 and wall > 0\n    realized = round(mkt \/ wall, 2) if ok else None\n\n    return {\n        \"emitted\": st[\"emitted\"],\n        \"batches\": st[\"batches\"],\n        \"mean_batch\": round(\n            st[\"emitted\"] \/ max(1, st[\"batches\"]), 1\n        ),\n        \"market_s\": round(mkt, 3),\n        \"wall_s\": round(wall, 3),\n        \"requested_speed\": st[\"speed\"],\n        \"realized_speed\": realized,\n        \"speed_error_pct\": (\n            round(\n                100 * (realized - st[\"speed\"]) \/ st[\"speed\"],\n                2\n            )\n            if ok else None\n        ),\n        \"lateness_p50_ms\": round(\n            float(np.percentile(a, 50)), 2\n        ),\n        \"lateness_p95_ms\": round(\n            float(np.percentile(a, 95)), 2\n        ),\n        \"lateness_max_ms\": round(\n            float(a.max()), 2\n        ),\n        \"reanchor_batches_dropped\": st[\"dropped\"]\n    }\n\n\nasync def replay_batches(\n    tape,\n    clock,\n    start,\n    stats,\n    max_batch=4096\n):\n    i, n = start, len(tape)\n    last_epoch = clock.epoch\n\n    if stats[\"wall0\"] is None:\n        stats[\"wall0\"] = time.monotonic()\n        stats[\"market0\"] = int(tape.ts[start])\n\n    while i < n:\n        if not clock.running:\n            await asyncio.sleep(0.005)\n            continue\n\n        now = time.monotonic()\n\n        j = min(\n            int(\n                np.searchsorted(\n                    tape.ts,\n                    clock.now_ms(now),\n                    side=\"right\"\n                )\n            ),\n            n,\n            i + max_batch\n        )\n\n        if j > i and not clock.running:\n            continue\n\n        if j > i:\n            if clock.epoch == last_epoch:\n                targets = clock.wall_for(\n                    tape.ts[i:j].astype(np.float64)\n                )\n\n                stats[\"lateness\"].extend(\n                    ((now - targets) * 1000).tolist()\n                )\n            else:\n                stats[\"dropped\"] += 1\n                last_epoch = clock.epoch\n\n            stats[\"emitted\"] += j - i\n            stats[\"batches\"] += 1\n            stats[\"market1\"] = int(tape.ts[j - 1])\n\n            yield i, j\n            i = j\n            continue\n\n        wait = clock.wall_for(float(tape.ts[i])) - now\n\n        await asyncio.sleep(\n            wait if wait > MIN_SLEEP_S else 0\n        )\n<\/code><\/pre>\n<p><code>now_ms()<\/code>    \u06cc\u06c1 \u0622\u067e \u06a9\u0648 \u0628\u062a\u0627\u062a\u0627 \u06c1\u06d2 \u06a9\u06c1 \u0645\u0648\u062c\u0648\u062f\u06c1 \u06a9\u06be\u06cc\u0644 \u062a\u0627\u0631\u06cc\u062e\u06cc \u0628\u0627\u0632\u0627\u0631 \u06a9\u06d2 \u0627\u0648\u0642\u0627\u062a \u0645\u06cc\u06ba \u06a9\u06c1\u0627\u06ba \u06c1\u06d2\u06d4 <code>wall_for()<\/code> \u06cc\u06c1 \u0631\u06cc\u0648\u0631\u0633 \u06a9\u0646\u0648\u0631\u0698\u0646 \u06a9\u0631\u062a\u0627 \u06c1\u06d2 \u0627\u0648\u0631 \u0645\u0634\u06cc\u0646 \u06a9\u06cc \u0645\u0648\u0646\u0648\u0679\u0648\u0646\u06a9 \u06a9\u0644\u0627\u06a9 \u06a9\u0648 \u0628\u062a\u0627\u062a\u0627 \u06c1\u06d2 \u06a9\u06c1 \u06c1\u0633\u0679\u0631\u06cc \u0679\u0627\u0626\u0645 \u0627\u0633\u0679\u06cc\u0645\u067e \u06a9\u0628 \u062e\u062a\u0645 \u06c1\u0648\u0646\u0627 \u0686\u0627\u06c1\u06cc\u06d2\u06d4<\/p>\n<p>\u0622\u067e \u0628\u0646\u06cc\u0627\u062f\u06cc \u0679\u06cc\u067e \u0645\u06cc\u06ba \u062a\u0631\u0645\u06cc\u0645 \u06a9\u06cc\u06d2 \u0628\u063a\u06cc\u0631 \u0627\u0633 \u0645\u06cc\u067e\u0646\u06af \u06a9\u0648 \u0631\u0648\u06a9 \u0633\u06a9\u062a\u06d2 \u06c1\u06cc\u06ba\u060c \u062f\u0648\u0628\u0627\u0631\u06c1 \u0634\u0631\u0648\u0639 \u06a9\u0631 \u0633\u06a9\u062a\u06d2 \u06c1\u06cc\u06ba\u060c \u0631\u0641\u062a\u0627\u0631 \u06a9\u0648 \u062a\u0628\u062f\u06cc\u0644 \u06a9\u0631 \u0633\u06a9\u062a\u06d2 \u06c1\u06cc\u06ba \u0627\u0648\u0631 \u062f\u0648\u0628\u0627\u0631\u06c1 \u0645\u0646\u062c\u0645\u062f \u06a9\u0631\u0646\u06d2 \u06a9\u06cc \u06a9\u0648\u0634\u0634 \u06a9\u0631 \u0633\u06a9\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4<\/p>\n<p>\u0627\u06cc\u06a9 \u0627\u0648\u0631 \u0627\u06c1\u0645 \u062d\u0635\u06c1 \u0628\u06cc\u0686 \u067e\u0631\u0648\u0633\u06cc\u0633\u0646\u06af \u06c1\u06d2\u06d4 \u0627\u0639\u0644\u06cc \u0631\u06cc\u0641\u0631\u06cc\u0634 \u0631\u06cc\u0679 \u067e\u0631\u060c \u06c1\u0631 \u0644\u06cc\u0646 \u062f\u06cc\u0646 \u06a9\u06d2 \u0644\u06cc\u06d2 \u0627\u06cc\u06a9 \u0646\u06cc\u0646\u062f \u06a9\u0627 \u0648\u0642\u062a \u0645\u0642\u0631\u0631 \u06a9\u0631\u0646\u06d2 \u0633\u06d2 \u0627\u06c1\u0645 \u0627\u0648\u0648\u0631 \u06c1\u06cc\u0688 \u06c1\u0648\u062a\u0627 \u06c1\u06d2\u06d4 <code>replay_batches()<\/code> \u0627\u0633 \u06a9\u06d2 \u0628\u062c\u0627\u0626\u06d2\u060c \u06cc\u06c1 \u067e\u0648\u0686\u06be\u062a\u0627 \u06c1\u06d2 \u06a9\u06c1 \u0645\u0627\u0631\u06a9\u06cc\u0679 \u06a9\u0627 \u0648\u0642\u062a \u06a9\u0633 \u062d\u062f \u062a\u06a9 \u0622\u06af\u06d2 \u0628\u0691\u06be\u0627 \u06c1\u06d2 \u0627\u0648\u0631 \u06a9\u0646\u0641\u06cc\u06af\u0631 \u0634\u062f\u06c1 \u0628\u06cc\u0686 \u0633\u0627\u0626\u0632 \u062a\u06a9 \u062a\u0645\u0627\u0645 \u067e\u06c1\u0644\u06d2 \u0633\u06d2 \u0628\u0646\u062f \u062a\u062c\u0627\u0631\u062a \u062c\u0627\u0631\u06cc \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<p>\u0627\u06af\u0631 \u0627\u06cc\u0648\u0646\u0679 \u06a9\u0627 \u0644\u0648\u067e \u062a\u06be\u0648\u0691\u0627 \u0633\u0627 \u067e\u06cc\u0686\u06be\u06d2 \u06c1\u0648 \u062c\u0627\u062a\u0627 \u06c1\u06d2\u060c \u062a\u0648 \u0627\u06af\u0644\u0627 \u0628\u06cc\u0686 \u0627\u06cc\u06a9 \u0627\u0648\u0631 \u0645\u0635\u0646\u0648\u0639\u06cc \u062a\u0627\u062e\u06cc\u0631 \u0645\u062a\u0639\u0627\u0631\u0641 \u06a9\u0631\u0627\u0646\u06d2 \u06a9\u06d2 \u0628\u062c\u0627\u0626\u06d2 \u0628\u0691\u0627 \u06c1\u0648 \u06af\u0627\u06d4<\/p>\n<h3 id=\"heading-benchmark-the-replay-clock\">\u0648\u0627\u0686 \u0628\u06cc\u0646\u0686 \u0645\u0627\u0631\u06a9\u0646\u06af \u06a9\u06be\u06cc\u0644\u06cc\u06ba<\/h3>\n<p>\u0627\u0628 \u067e\u0686\u06be\u0644\u06d2 \u062d\u0635\u06d2 \u0645\u06cc\u06ba \u0628\u0646\u0627\u0626\u06cc \u06af\u0626\u06cc \u062f\u0648\u067e\u06c1\u0631 \u06a9\u06cc \u0679\u06cc\u067e \u0644\u0648\u0688 \u06a9\u0631\u06cc\u06ba \u0627\u0648\u0631 \u0645\u0627\u0631\u06a9\u06cc\u0679 \u0679\u0627\u0626\u0645 \u06a9\u06d2 \u067e\u06c1\u0644\u06d2 30 \u0633\u06cc\u06a9\u0646\u0688\u0632 \u06a9\u06cc \u062c\u0627\u0646\u0686 \u06a9\u0631\u06cc\u06ba\u06d4<\/p>\n<pre><code class=\"language-python\">import numpy as np\n\nfrom replay import config\nfrom replay.events import TradeTape\nfrom replay.clock import (\n    ReplayClock,\n    replay_batches,\n    new_stats,\n    summarize\n)\n\ntape = TradeTape.load(\n    config.PROCESSED \/ \"AAPL_2026-07-15_quiet15m.npz\"\n)\n\nend = int(\n    np.searchsorted(\n        tape.ts,\n        tape.ts[0] + 30_000,\n        side=\"right\"\n    )\n)\n\nprint(\n    f\"{end:,} events in the first \"\n    \"30 market seconds of AAPL quiet15mn\"\n)\n\nasync def measure():\n    print(\n        f\"{'speed':>6} {'market_s':>9} \"\n        f\"{'wall_s':>8} {'realized':>9} \"\n        f\"{'err_%':>7} {'p50_ms':>7} \"\n        f\"{'p95_ms':>7} {'max_ms':>7}\"\n    )\n\n    for speed in [1, 10, 50, 100]:\n        clock = ReplayClock(\n            tape.ts[0],\n            speed\n        ).start()\n\n        st = new_stats(speed)\n\n        async for i, j in replay_batches(\n            tape,\n            clock,\n            0,\n            st\n        ):\n            if j >= end:\n                break\n\n        r = summarize(st)\n\n        print(\n            f\"{r['requested_speed']:>6} \"\n            f\"{r['market_s']:>9} \"\n            f\"{r['wall_s']:>8} \"\n            f\"{r['realized_speed']:>9} \"\n            f\"{r['speed_error_pct']:>7} \"\n            f\"{r['lateness_p50_ms']:>7} \"\n            f\"{r['lateness_p95_ms']:>7} \"\n            f\"{r['lateness_max_ms']:>7}\"\n        )\n\nawait measure()\n<\/code><\/pre>\n<p>\u0639\u0645\u0644 \u062f\u0631\u0622\u0645\u062f \u06a9\u06d2 \u062d\u0642\u06cc\u0642\u06cc \u0646\u062a\u0627\u0626\u062c \u062f\u0631\u062c \u0630\u06cc\u0644 \u06c1\u06cc\u06ba:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/umang.pk\/wp-content\/uploads\/2026\/08\/1787822510_325_\u0645\u0627\u0631\u06a9\u06cc\u0679-\u0679\u0627\u0626\u0645-\u0645\u0634\u06cc\u0646-\u0628\u0646\u0627\u0646\u0627-\u0627\u0632\u06af\u0631-\u0627\u0648\u0631-\u0648\u06cc\u0628-\u0633\u0627\u06a9\u0679-\u06a9\u0627-\u0627\u0633\u062a\u0639\u0645\u0627\u0644.png\" alt=\"15 \u0645\u0646\u0679 \u062e\u0627\u0645\u0648\u0634\u06cc \u0633\u06d2 \u0686\u0644\u0627\u0626\u06cc\u06ba\u06d4\" style=\"display:block;margin:0 auto\" width=\"600\" height=\"400\" loading=\"lazy\" title=\"\"><\/p>\n<p>\u062a\u0627\u0631\u06cc\u062e\u06cc \u0628\u0627\u0632\u0627\u0631 \u06a9\u06d2 \u0627\u0648\u0642\u0627\u062a \u0645\u06cc\u06ba 30 \u0633\u06cc\u06a9\u0646\u0688 \u0644\u06af\u06d2\u06d4 <code>30.001<\/code> 1x \u0645\u0648\u0645 \u0628\u062a\u06cc\u060c <code>3.001<\/code> 10x \u067e\u0631 \u0633\u06cc\u06a9\u0646\u0688\u060c <code>0.6<\/code> 50x \u067e\u0631 \u0633\u06cc\u06a9\u0646\u0688\u060c <code>0.3<\/code> \u0633\u06cc\u06a9\u0646\u0688 \u0645\u06cc\u06ba 100x \u0644\u06c1\u0630\u0627\u060c \u062d\u0627\u0635\u0644 \u06a9\u0631\u062f\u06c1 \u0631\u0641\u062a\u0627\u0631 \u06c1\u0645\u0627\u0631\u06cc \u062f\u0631\u062e\u0648\u0627\u0633\u062a \u06a9\u06d2 \u0628\u06c1\u062a \u0642\u0631\u06cc\u0628 \u0631\u06c1\u06cc\u06d4<\/p>\n<p>\u062a\u0627\u062e\u06cc\u0631 \u06a9\u06cc \u0642\u06cc\u0645\u062a \u0622\u067e \u06a9\u0648 \u0628\u062a\u0627\u062a\u06cc \u06c1\u06d2 \u06a9\u06c1 \u0634\u06cc\u0688\u0648\u0644\u0631 \u0646\u06d2 \u0627\u0646\u0641\u0631\u0627\u062f\u06cc \u0627\u06cc\u0648\u0646\u0679 \u06a9\u06cc \u0622\u062e\u0631\u06cc \u062a\u0627\u0631\u06cc\u062e \u06a9\u062a\u0646\u06cc \u0686\u06be\u0648\u0679 \u062f\u06cc \u06c1\u06d2\u06d4 \u0645\u062b\u0627\u0644 \u06a9\u06d2 \u0637\u0648\u0631 \u067e\u0631\u060c 10x \u067e\u0631 \u0627\u0648\u0633\u0637 \u062a\u0627\u062e\u06cc\u0631 \u06a9\u0627 \u0648\u0642\u062a \u06c1\u06d2: <code>0.36 ms<\/code>95\u0648\u0627\u06ba \u067e\u0631\u0633\u0646\u0679\u0627\u0626\u0644 \u06c1\u06d2\u06d4 <code>1.12 ms<\/code>\u0627\u0633 \u0631\u0646 \u0633\u06d2 \u0628\u062f\u062a\u0631\u06cc\u0646 \u0645\u0634\u0627\u06c1\u062f\u06c1 \u06c1\u06d2\u06d4 <code>11.75 ms<\/code>.<\/p>\n<p>\u06cc\u06c1 \u0646\u0645\u0628\u0631 \u062e\u0648\u062f \u0631\u06cc\u0641\u0631\u06cc\u0634 \u06af\u06be\u0691\u06cc \u06a9\u06cc \u067e\u06cc\u0645\u0627\u0626\u0634 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4 \u06cc\u06c1 \u0627\u06cc\u0646\u0688 \u0679\u0648 \u0627\u06cc\u0646\u0688 \u0648\u06cc\u0628 \u0633\u0627\u06a9\u0679 \u0644\u06cc\u0679\u06cc\u0646\u0633\u06cc \u067e\u06cc\u0645\u0627\u0626\u0634 \u0646\u06c1\u06cc\u06ba \u06c1\u06d2\u060c \u062c\u0648 \u0627\u0628 \u0628\u06be\u06cc \u0627\u0632\u06af\u0631 \u0645\u06cc\u06ba \u0627\u06cc\u0648\u0646\u0679 \u0644\u0648\u067e\u0633 \u06a9\u06d2 \u0644\u06cc\u06d2 \u0628\u06c1\u062a\u0631\u06cc\u0646 \u0634\u06cc\u0688\u0648\u0644\u0646\u06af \u06c1\u06d2\u060c \u0646\u06c1 \u06a9\u06c1 \u0627\u06cc\u06a9\u0633\u0686\u06cc\u0646\u062c \u06af\u0631\u06cc\u0688 \u0679\u0627\u0626\u0645\u0646\u06af\u06d4<\/p>\n<h2 id=\"heading-add-playback-controls-with-a-replay-session\">\u067e\u0644\u06d2 \u0628\u06cc\u06a9 \u0633\u06cc\u0634\u0646\u0632 \u0645\u06cc\u06ba \u067e\u0644\u06d2 \u0628\u06cc\u06a9 \u06a9\u0646\u0679\u0631\u0648\u0644\u0632 \u0634\u0627\u0645\u0644 \u06a9\u0631\u06cc\u06ba\u06d4<\/h2>\n<p>\u0631\u06cc \u067e\u0644\u06d2 \u06a9\u0644\u0627\u06a9 \u06a9\u0648 \u0645\u0639\u0644\u0648\u0645 \u06c1\u0648\u062a\u0627 \u06c1\u06d2 \u06a9\u06c1 \u0688\u06cc\u0644 \u06a9\u0628 \u06c1\u06d2\u060c \u0644\u06cc\u06a9\u0646 \u06cc\u06c1 \u0646\u06c1\u06cc\u06ba \u062c\u0627\u0646\u062a\u06cc \u06a9\u06c1 \u0645\u0648\u062c\u0648\u062f\u06c1 \u0631\u06cc \u067e\u0644\u06d2 \u06a9\u06c1\u0627\u06ba \u06c1\u06d2 \u06cc\u0627 \u0631\u06cc \u067e\u0644\u06d2 \u06a9\u06cc\u0627 \u062c\u0627\u0646\u0627 \u0686\u0627\u06c1\u06cc\u06d2\u06d4 \u0679\u06cc\u067e \u06a9\u06d2 \u0645\u0627\u0644\u06a9 \u06c1\u0648\u0646\u06d2\u060c \u0645\u0648\u062c\u0648\u062f\u06c1 \u06a9\u0631\u0633\u0631 \u06a9\u0648 \u0679\u0631\u06cc\u06a9 \u06a9\u0631\u0646\u06d2\u060c \u0627\u06cc\u0648\u0646\u0679 \u06a9\u06cc \u0642\u0637\u0627\u0631 \u06a9\u0648 \u0645\u0646\u0638\u0645 \u06a9\u0631\u0646\u06d2\u060c \u0627\u0648\u0631 \u06a9\u0646\u0679\u0631\u0648\u0644\u0632 \u06a9\u0648 \u0645\u0631\u0628\u0648\u0637 \u06a9\u0631\u0646\u06d2 \u062c\u06cc\u0633\u06d2 \u06a9\u06c1 \u0634\u0631\u0648\u0639\u060c \u062a\u0648\u0642\u0641\u060c \u062f\u0648\u0628\u0627\u0631\u06c1 \u0634\u0631\u0648\u0639\u060c \u0631\u0641\u062a\u0627\u0631 \u06a9\u0648 \u062a\u0628\u062f\u06cc\u0644 \u06a9\u0631\u0646\u06d2\u060c \u062a\u0644\u0627\u0634 \u06a9\u0631\u0646\u06d2 \u0627\u0648\u0631 \u0631\u06a9\u0646\u06d2 \u06a9\u06d2 \u0644\u06cc\u06d2 \u0627\u06cc\u06a9 \u0627\u0648\u0631 \u067e\u0631\u062a \u06a9\u06cc \u0636\u0631\u0648\u0631\u062a \u06c1\u06d2\u06d4<\/p>\n<p>\u0645\u0646\u0637\u0642 \u0645\u0646\u062f\u0631\u062c\u06c1 \u0630\u06cc\u0644 \u06c1\u06d2: <code>replay\/session.py<\/code>:<\/p>\n<pre><code class=\"language-plaintext\">market-time-machine\/\n\u2514\u2500\u2500 replay\/\n    \u251c\u2500\u2500 config.py\n    \u251c\u2500\u2500 loader.py\n    \u251c\u2500\u2500 events.py\n    \u251c\u2500\u2500 clock.py\n    \u2514\u2500\u2500 session.py\n<\/code><\/pre>\n<p>\u0627\u0633 \u0641\u0631\u0642 \u06a9\u0648 \u0648\u0627\u0636\u062d \u0631\u06a9\u06be\u0646\u0627 \u0645\u0641\u06cc\u062f \u06c1\u06d2 \u06a9\u06c1 \u06af\u06be\u0691\u06cc \u0648\u0642\u062a \u06a9\u06cc \u0645\u0627\u0644\u06a9 \u06c1\u06d2 \u0627\u0648\u0631 \u0633\u06cc\u0634\u0646 \u0631\u06cc\u0627\u0633\u062a \u06a9\u0627 \u0645\u0627\u0644\u06a9 \u06c1\u06d2\u06d4<\/p>\n<p>\u0627\u06cc\u06a9 \u067e\u0644\u06d2 \u0628\u06cc\u06a9 \u0633\u06cc\u0634\u0646 \u0631\u06cc\u0627\u0633\u062a\u0648\u06ba \u06a9\u06d2 \u0627\u06cc\u06a9 \u0686\u06be\u0648\u0679\u06d2 \u0633\u06cc\u0679 \u0633\u06d2 \u06af\u0632\u0631\u062a\u0627 \u06c1\u06d2:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/umang.pk\/wp-content\/uploads\/2026\/08\/1787822510_874_\u0645\u0627\u0631\u06a9\u06cc\u0679-\u0679\u0627\u0626\u0645-\u0645\u0634\u06cc\u0646-\u0628\u0646\u0627\u0646\u0627-\u0627\u0632\u06af\u0631-\u0627\u0648\u0631-\u0648\u06cc\u0628-\u0633\u0627\u06a9\u0679-\u06a9\u0627-\u0627\u0633\u062a\u0639\u0645\u0627\u0644.png\" alt=\"\u0633\u06cc\u0634\u0646 \u0632\u0646\u062f\u06af\u06cc \u0633\u0627\u0626\u06cc\u06a9\u0644\" style=\"display:block;margin:0 auto\" width=\"600\" height=\"400\" loading=\"lazy\" title=\"\"><\/p>\n<h3 id=\"heading-create-replaysessionpy\">\u0628\u0646\u0627\u0646\u0627 <code>replay\/session.py<\/code><\/h3>\n<p>\u0628\u0646\u0627\u0646\u0627 <code>replay\/session.py<\/code>:<\/p>\n<pre><code class=\"language-python\">import asyncio, collections, contextlib, uuid\nfrom enum import Enum\n\nfrom .clock import ReplayClock, replay_batches, new_stats, summarize\n\nclass State(str, Enum):\n    CREATED, RUNNING, PAUSED, COMPLETED, STOPPED = (\n        \"created\", \"running\", \"paused\", \"completed\", \"stopped\"\n    )\n\nclass ReplaySession:\n    PRIORITY = {\n        \"paused\", \"resumed\", \"speed_changed\",\n        \"replay_reset\", \"session_stopped\"\n    }\n\n    def __init__(self, tape, speed=1.0, warmup_ms=120_000, maxsize=256):\n        self.id = uuid.uuid4().hex[:12]\n        self.tape = tape\n        self.warmup_ms = warmup_ms\n        self.maxsize = maxsize\n\n        self.state = State.CREATED\n        self.cursor = 0\n        self.clock = ReplayClock(tape.ts[0], speed)\n        self.stats = new_stats(speed)\n\n        self._q = collections.deque()\n        self._wake = asyncio.Event()\n        self._task = None\n        self._epoch = 0\n        self._lock = asyncio.Lock()\n\n    def info(self):\n        lo, hi = self.tape.span()\n\n        return {\n            \"session_id\": self.id,\n            \"symbol\": self.tape.symbol,\n            \"state\": self.state.value,\n            \"speed\": self.clock.speed,\n            \"cursor\": self.cursor,\n            \"total_events\": len(self.tape),\n            \"market_ts_ms\": int(\n                self.tape.ts[min(self.cursor, len(self.tape)-1)]\n            ),\n            \"session_start_ms\": lo,\n            \"session_end_ms\": hi,\n            \"queued\": len(self._q)\n        }\n\n    def _ctrl(self, kind, **kw):\n        msg = {\n            \"type\": kind,\n            \"session_id\": self.id,\n            \"source\": \"replay\",\n            **kw\n        }\n\n        if kind in self.PRIORITY:\n            self._q.appendleft(msg)\n        else:\n            self._q.append(msg)\n\n        self._wake.set()\n\n    async def _put(self, msg):\n        while len(self._q) >= self.maxsize:\n            self._wake.set()\n            await asyncio.sleep(0)\n\n        self._q.append(msg)\n        self._wake.set()\n\n    async def _kill(self):\n        t, self._task = self._task, None\n\n        if t and not t.done():\n            t.cancel()\n\n            with contextlib.suppress(\n                asyncio.CancelledError,\n                Exception\n            ):\n                await t\n\n    async def start(self):\n        self.clock.start()\n        self.state = State.RUNNING\n        self._task = asyncio.create_task(self._run())\n\n        self._ctrl(\n            \"session_started\",\n            info=self.info()\n        )\n\n        return self.info()\n\n    async def pause(self):\n        if self.state is State.RUNNING:\n            async with self._lock:\n                self.clock.pause()\n                self.stats[\"dropped\"] += 1\n                self.state = State.PAUSED\n\n                self._ctrl(\n                    \"paused\",\n                    market_ts_ms=self.info()[\"market_ts_ms\"]\n                )\n\n        return self.info()\n\n    async def resume(self):\n        if self.state is State.PAUSED:\n            async with self._lock:\n                self.clock.resume()\n                self.state = State.RUNNING\n\n                if self._task is None or self._task.done():\n                    self._task = asyncio.create_task(self._run())\n\n                self._ctrl(\n                    \"resumed\",\n                    market_ts_ms=self.info()[\"market_ts_ms\"]\n                )\n\n        return self.info()\n\n    async def set_speed(self, speed):\n        async with self._lock:\n            old = self.clock.speed\n            self.clock.set_speed(speed)\n            self.stats[\"speed\"] = speed\n\n            self._ctrl(\n                \"speed_changed\",\n                old_speed=old,\n                new_speed=speed\n            )\n\n        return self.info()\n\n    async def seek(self, target_ms):\n        was = self.state\n        await self._kill()\n\n        async with self._lock:\n            idx = max(\n                0,\n                min(\n                    self.tape.index_at(target_ms),\n                    len(self.tape)-1\n                )\n            )\n\n            self._epoch += 1\n            self.cursor = idx\n            self.state = State.PAUSED\n            self.clock.pause()\n\n            warm = max(\n                0,\n                self.tape.index_at(\n                    int(self.tape.ts[idx]) - self.warmup_ms\n                )\n            )\n\n            purged = sum(\n                1 for m in self._q\n                if m.get(\"type\") == \"trade\"\n            )\n\n            self._q = collections.deque(\n                m for m in self._q\n                if m.get(\"type\") != \"trade\"\n            )\n\n            self._ctrl(\n                \"replay_reset\",\n                reason=\"seek\",\n                target_timestamp_ms=int(self.tape.ts[idx]),\n                warmup_from_ms=int(self.tape.ts[warm]),\n                warmup_events=idx-warm,\n                purged_stale_events=purged,\n                epoch=self._epoch\n            )\n\n        for k in range(warm, idx):\n            await self._put({\n                **self.tape[k].to_wire(),\n                \"warmup\": True\n            })\n\n        self._ctrl(\n            \"warmup_complete\",\n            market_ts_ms=int(self.tape.ts[idx])\n        )\n\n        async with self._lock:\n            self.clock.seek(float(self.tape.ts[idx]))\n\n            if was is State.RUNNING:\n                self.clock.start()\n                self.state = State.RUNNING\n                self._task = asyncio.create_task(self._run())\n\n        return self.info()\n\n    async def stop(self):\n        self.state = State.STOPPED\n        await self._kill()\n\n        self._ctrl(\n            \"session_stopped\",\n            info=self.info(),\n            timing=summarize(self.stats)\n        )\n\n        return self.info()\n\n    async def _run(self):\n        epoch = self._epoch\n\n        async for i, j in replay_batches(\n            self.tape,\n            self.clock,\n            self.cursor,\n            self.stats\n        ):\n            if self._epoch != epoch or self.state is State.STOPPED:\n                return\n\n            for k in range(i, j):\n                await self._put(self.tape[k].to_wire())\n                self.cursor = k+1\n\n        if self._epoch == epoch and self.cursor >= len(self.tape):\n            self.state = State.COMPLETED\n\n            self._ctrl(\n                \"session_completed\",\n                info=self.info(),\n                timing=summarize(self.stats)\n            )\n\n    async def events(self):\n        while True:\n            if not self._q:\n                self._wake.clear()\n                await self._wake.wait()\n                continue\n\n            m = self._q.popleft()\n            yield m\n\n            if m.get(\"type\") in (\n                \"session_completed\",\n                \"session_stopped\"\n            ):\n                return\n<\/code><\/pre>\n<p>\u0633\u06cc\u0634\u0646 \u0631\u06cc\u0627\u0633\u062a \u06a9\u06d2 \u0627\u06c1\u0645 \u062d\u0635\u06d2 \u06c1\u06cc\u06ba: <code>cursor<\/code>\u06cc\u06c1 \u062f\u0631\u062c \u0630\u06cc\u0644 \u0645\u0642\u0627\u0645 \u06a9\u06cc \u0637\u0631\u0641 \u0627\u0634\u0627\u0631\u06c1 \u06a9\u0631\u062a\u0627 \u06c1\u06d2: <code>TradeTape<\/code>. \u067e\u0631\u0648\u0688\u06cc\u0648\u0633\u0631\u0648\u06ba \u06a9\u06cc \u0637\u0631\u0641 \u0633\u06d2 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u06cc\u0627 \u062c\u0627\u062a\u0627 \u06c1\u06d2 <code>replay_batches()<\/code> \u06af\u06be\u0691\u06cc \u06a9\u06cc \u067e\u0631\u062a \u06c1\u0631 \u0679\u06cc\u067e \u06a9\u06cc \u067e\u0648\u0632\u06cc\u0634\u0646 \u06a9\u0648 \u0648\u0627\u0626\u0631 \u0679\u0631\u0627\u0646\u0632\u06cc\u06a9\u0634\u0646 \u0627\u06cc\u0648\u0646\u0679 \u0645\u06cc\u06ba \u062a\u0628\u062f\u06cc\u0644 \u06a9\u0631\u062a\u06cc \u06c1\u06d2 \u0627\u0648\u0631 \u0627\u0633\u06d2 \u0633\u06cc\u0634\u0646 \u06a9\u06cc \u0642\u0637\u0627\u0631 \u0645\u06cc\u06ba \u0631\u06a9\u06be\u062a\u06cc \u06c1\u06d2\u06d4<\/p>\n<p>\u0645\u0648\u0642\u0648\u0641 \u06a9\u0631\u0633\u0631 \u06a9\u0648 \u062a\u0628\u062f\u06cc\u0644 \u06a9\u06cc\u06d2 \u0628\u063a\u06cc\u0631 \u06af\u06be\u0691\u06cc \u06a9\u0648 \u0645\u0646\u062c\u0645\u062f \u06a9\u0631 \u062f\u06cc\u062a\u0627 \u06c1\u06d2\u06d4 \u062f\u0648\u0628\u0627\u0631\u06c1 \u06a9\u06be\u0644\u0646\u06d2 \u067e\u0631\u060c \u06af\u06be\u0691\u06cc \u06a9\u0648 \u0627\u06cc\u06a9 \u0646\u06cc\u0627 \u0648\u0627\u0644 \u06a9\u0644\u0627\u06a9 \u0627\u06cc\u0646\u06a9\u0631 \u062f\u06cc\u0627 \u062c\u0627\u0626\u06d2 \u06af\u0627 \u0627\u0648\u0631 \u0627\u0633\u06cc \u062a\u0627\u0631\u06cc\u062e\u06cc \u0645\u0642\u0627\u0645 \u067e\u0631 \u062c\u0627\u0631\u06cc \u0631\u06c1\u06d2 \u06af\u0627\u06d4 \u0631\u0641\u062a\u0627\u0631 \u06a9\u06cc \u062a\u0628\u062f\u06cc\u0644\u06cc\u0627\u06ba \u0628\u06be\u06cc \u0627\u0633\u06cc \u0637\u0631\u062d \u06a9\u0627\u0645 \u06a9\u0631\u062a\u06cc \u06c1\u06cc\u06ba\u06d4 \u06af\u06be\u0691\u06cc \u067e\u06c1\u0644\u06d2 \u0645\u0648\u062c\u0648\u062f\u06c1 \u067e\u0644\u06d2 \u0628\u06cc\u06a9 \u0679\u0627\u0626\u0645 \u0627\u0633\u0679\u06cc\u0645\u067e \u067e\u0631 \u0644\u0627\u06a9 \u06a9\u0631\u062a\u06cc \u06c1\u06d2 \u0627\u0648\u0631 \u067e\u06be\u0631 \u0627\u0633 \u0645\u0642\u0627\u0645 \u0633\u06d2 \u0646\u0626\u06cc \u0631\u0641\u062a\u0627\u0631 \u06a9\u0627 \u0627\u0637\u0644\u0627\u0642 \u06a9\u0631\u062a\u06cc \u06c1\u06d2\u06d4<\/p>\n<p>\u0642\u0637\u0627\u0631\u0648\u06ba \u0645\u06cc\u06ba \u0635\u0631\u0641 \u0644\u06cc\u0646 \u062f\u06cc\u0646 \u0633\u06d2 \u0632\u06cc\u0627\u062f\u06c1 \u0634\u0627\u0645\u0644 \u06c1\u06cc\u06ba\u06d4 \u06a9\u0646\u0679\u0631\u0648\u0644 \u062c\u06cc\u0633\u06d2 <code>paused<\/code>, <code>resumed<\/code>, <code>speed_changed<\/code>\u0627\u0648\u0631 <code>replay_reset<\/code> \u0627\u0633 \u06a9\u0627 \u0645\u0637\u0644\u0628 \u06c1\u06d2 \u06a9\u06c1 \u0688\u0627\u0624\u0646 \u0627\u0633\u0679\u0631\u06cc\u0645 \u0635\u0627\u0631\u0641\u06cc\u0646 \u0644\u06cc\u0646 \u062f\u06cc\u0646 \u06a9\u06d2 \u0679\u0627\u0626\u0645 \u0627\u0633\u0679\u06cc\u0645\u067e \u0633\u06d2 \u0627\u0646\u062f\u0627\u0632\u06c1 \u0644\u06af\u0627\u0646\u06d2 \u06a9\u06d2 \u0628\u062c\u0627\u0626\u06d2 \u067e\u0644\u06d2 \u0628\u06cc\u06a9 \u062d\u0627\u0644\u062a \u0645\u06cc\u06ba \u06c1\u0648\u0646\u06d2 \u0648\u0627\u0644\u06cc \u062a\u0628\u062f\u06cc\u0644\u06cc\u0648\u06ba \u067e\u0631 \u0631\u062f \u0639\u0645\u0644 \u0638\u0627\u06c1\u0631 \u06a9\u0631 \u0633\u06a9\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4<\/p>\n<p><code>seek()<\/code>    \u06cc\u06c1 \u0633\u0628 \u0633\u06d2 \u0632\u06cc\u0627\u062f\u06c1 \u0645\u062a\u0639\u0644\u0642\u06c1 \u06a9\u0646\u0679\u0631\u0648\u0644\u0632 \u06c1\u06cc\u06ba\u06d4 \u0645\u0648\u062c\u0648\u062f\u06c1 \u067e\u0631\u0648\u0688\u06cc\u0648\u0633\u0631 \u06a9\u0648 \u0631\u0648\u06a9\u062a\u0627 \u06c1\u06d2 \u0627\u0648\u0631 \u0645\u0637\u0644\u0648\u0628\u06c1 \u0645\u0642\u0627\u0645 \u06a9\u0627 \u067e\u062a\u06c1 \u0644\u06af\u0627\u062a\u0627 \u06c1\u06d2\u06d4 <code>TradeTape.index_at()<\/code>\u067e\u0631\u0627\u0646\u06d2 \u0627\u0633\u0679\u06cc\u0646\u0688 \u0628\u0627\u0626\u06cc \u0644\u06cc\u0646 \u062f\u06cc\u0646 \u06a9\u0648 \u06c1\u0679\u0627\u062a\u0627 \u06c1\u06d2 \u0627\u0648\u0631 \u067e\u0644\u06d2 \u0628\u06cc\u06a9 \u06a9\u0648 \u062c\u0627\u0631\u06cc \u0631\u06a9\u06be\u0646\u06d2 \u0633\u06d2 \u067e\u06c1\u0644\u06d2 \u0648\u0627\u0631\u0645 \u0627\u067e \u0645\u062f\u062a \u06a9\u06d2 \u0644\u06cc\u06d2 \u062a\u06cc\u0627\u0631 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4 \u0622\u0626\u06cc\u06d2 \u062f\u06cc\u06a9\u06be\u062a\u06d2 \u06c1\u06cc\u06ba \u06a9\u06c1 \u0631\u06cc\u0627\u0633\u062a\u06cc \u0635\u0627\u0631\u0641\u06cc\u0646 \u06a9\u0648 \u062a\u0639\u06cc\u0646\u0627\u062a \u06a9\u0631\u0646\u06d2 \u06a9\u06d2 \u0628\u0639\u062f \u0627\u0646\u06c1\u06cc\u06ba \u06af\u0631\u0645 \u06a9\u0631\u0646\u06d2 \u06a9\u06cc \u0636\u0631\u0648\u0631\u062a \u06a9\u06cc\u0648\u06ba \u06c1\u06d2\u06d4<\/p>\n<p>\u0622\u067e\u0631\u06cc\u0634\u0646 \u0645\u06cc\u06ba \u06a9\u0648\u0626\u06cc \u0627\u0644\u06af \u0679\u0631\u0645\u06cc\u0646\u0644 \u0646\u06c1\u06cc\u06ba \u06c1\u06d2\u06d4 <code>ReplaySession<\/code> \u0627\u0633 \u0645\u0642\u0627\u0645 \u067e\u0631\u06d4 \u0627\u06cc\u06a9 \u0628\u0627\u0631 \u062c\u0628 \u0628\u0627\u0642\u06cc \u0633\u0633\u0679\u0645 \u0645\u0646\u0633\u0644\u06a9 \u06c1\u0648 \u062c\u0627\u062a\u0627 \u06c1\u06d2\u060c \u062a\u0648 \u06c1\u0645 \u0627\u0646 \u06a9\u0646\u0679\u0631\u0648\u0644\u0632 \u06a9\u0648 \u0627\u0635\u0644 API \u0627\u0648\u0631 WebSocket \u0627\u0633\u0679\u0631\u06cc\u0645\u0632 \u06a9\u06d2 \u0630\u0631\u06cc\u0639\u06d2 \u0627\u0646\u062c\u0627\u0645 \u062f\u06cc\u06ba \u06af\u06d2\u06d4<\/p>\n<h2 id=\"heading-expose-the-replay-with-fastapi-and-websockets\">\u0641\u0627\u0633\u0679 \u0627\u06d2 \u067e\u06cc \u0622\u0626\u06cc \u0627\u0648\u0631 \u0648\u06cc\u0628 \u0633\u0627\u06a9\u0679 \u06a9\u0627 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631\u062a\u06d2 \u06c1\u0648\u0626\u06d2 \u0631\u06cc \u067e\u0644\u06d2 \u06a9\u0648 \u0628\u06d2 \u0646\u0642\u0627\u0628 \u06a9\u0631\u0646\u0627<\/h2>\n<p>\u067e\u0644\u06d2 \u0628\u06cc\u06a9 \u0633\u06cc\u0634\u0646 \u0645\u06cc\u06ba \u0627\u0628 \u0648\u06c1 \u0633\u0628 \u06a9\u0686\u06be \u06c1\u0648\u062a\u0627 \u06c1\u06d2 \u062c\u0633 \u06a9\u06cc \u0622\u067e \u06a9\u0648 \u0631\u06cc\u06a9\u0627\u0631\u0688\u0646\u06af \u067e\u0644\u06d2 \u0628\u06cc\u06a9 \u06a9\u0648 \u06a9\u0646\u0679\u0631\u0648\u0644 \u06a9\u0631\u0646\u06d2 \u06a9\u06cc \u0636\u0631\u0648\u0631\u062a \u06c1\u0648\u062a\u06cc \u06c1\u06d2\u060c \u0644\u06cc\u06a9\u0646 \u06cc\u06c1 \u0627\u0628 \u0628\u06be\u06cc \u0635\u0631\u0641 Python \u0622\u0628\u062c\u06cc\u06a9\u0679 \u06a9\u06d2 \u0637\u0648\u0631 \u067e\u0631 \u0645\u0648\u062c\u0648\u062f \u06c1\u06d2\u06d4 \u06cc\u06c1 \u0627\u067e\u0646\u06d2 \u0627\u0631\u062f \u06af\u0631\u062f \u0627\u06cc\u06a9 \u0686\u06be\u0648\u0679\u06cc API \u067e\u0631\u062a \u0631\u06a9\u06be\u062a\u0627 \u06c1\u06d2 \u062a\u0627\u06a9\u06c1 \u062f\u0648\u0633\u0631\u06d2 \u067e\u0631\u0648\u06af\u0631\u0627\u0645 \u0633\u06cc\u0634\u0646\u0632 \u0628\u0646\u0627 \u0627\u0648\u0631 \u06a9\u0646\u0679\u0631\u0648\u0644 \u06a9\u0631 \u0633\u06a9\u06cc\u06ba \u0627\u0648\u0631 \u0646\u062a\u06cc\u062c\u06d2 \u0645\u06cc\u06ba \u0644\u06cc\u0646 \u062f\u06cc\u0646 \u06a9\u0627 \u0633\u0644\u0633\u0644\u06c1 \u062d\u0627\u0635\u0644 \u06a9\u0631 \u0633\u06a9\u06cc\u06ba\u06d4<\/p>\n<p>\u06cc\u06c1 \u0627\u0644\u06af \u0627\u0644\u06af \u062a\u06c1\u0648\u06ba \u067e\u0631 \u06c1\u06cc\u06ba\u06d4 <code>api\/<\/code> \u067e\u06cc\u06a9\u06cc\u062c:<\/p>\n<pre><code class=\"language-plaintext\">market-time-machine\/\n\u251c\u2500\u2500 replay\/\n\u2502   \u2514\u2500\u2500 ...\n\u2514\u2500\u2500 api\/\n    \u251c\u2500\u2500 __init__.py\n    \u251c\u2500\u2500 server.py\n    \u2514\u2500\u2500 run.py\n<\/code><\/pre>\n<p>\u06c1\u0645 \u062f\u0648 \u0645\u0648\u0627\u0635\u0644\u0627\u062a\u06cc \u0631\u0627\u0633\u062a\u06d2 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631\u062a\u06d2 \u06c1\u06cc\u06ba: REST \u0627\u06cc\u0646\u0688 \u067e\u0648\u0627\u0626\u0646\u0679\u0633 \u06a9\u0646\u0679\u0631\u0648\u0644 \u06c1\u0648\u0627\u0626\u06cc \u062c\u06c1\u0627\u0632 \u0628\u0646\u0627\u062a\u06d2 \u06c1\u06cc\u06ba \u0627\u0648\u0631 \u0627\u06cc\u06a9 \u0645\u0633\u062a\u0642\u0644 WebSocket \u0627\u06cc\u0648\u0646\u0679 \u06a9\u06d2 \u0633\u0644\u0633\u0644\u06d2 \u06a9\u0648 \u0644\u06d2 \u062c\u0627\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<pre><code class=\"language-plaintext\">Control plane\n\nPOST \/sessions\nPOST \/sessions\/{id}\/start\nPOST \/sessions\/{id}\/pause\nPOST \/sessions\/{id}\/resume\nPOST \/sessions\/{id}\/speed\nPOST \/sessions\/{id}\/seek\nPOST \/sessions\/{id}\/stop\n\n\nEvent stream\n\nWS \/sessions\/{id}\/stream\n<\/code><\/pre>\n<p>\u0644\u06c1\u0630\u0627\u060c \u0631\u0648\u06a9\u0646\u06d2 \u06cc\u0627 \u062a\u0644\u0627\u0634 \u06a9\u0631\u0646\u06d2 \u062c\u06cc\u0633\u06cc \u06a9\u0645\u0627\u0646\u0688\u0632 HTTP \u067e\u0631 \u067e\u06c1\u0646\u0686\u062a\u06cc \u06c1\u06cc\u06ba\u060c \u062c\u0628 \u06a9\u06c1 \u0644\u06cc\u0646 \u062f\u06cc\u0646 \u0627\u0648\u0631 \u067e\u0644\u06d2 \u0628\u06cc\u06a9 \u06a9\u0646\u0679\u0631\u0648\u0644 \u06a9\u06d2 \u0648\u0627\u0642\u0639\u0627\u062a WebSocket \u06a9\u06d2 \u0630\u0631\u06cc\u0639\u06d2 \u0635\u0627\u0631\u0641\u06cc\u0646 \u062a\u06a9 \u067e\u06c1\u0646\u0686\u062a\u06d2 \u0631\u06c1\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4<\/p>\n<h3 id=\"heading-create-apiserverpy\">\u0628\u0646\u0627\u0646\u0627 <code>api\/server.py<\/code><\/h3>\n<p>\u0628\u0646\u0627\u0646\u0627 <code>api\/server.py<\/code>:<\/p>\n<pre><code class=\"language-python\">from fastapi import FastAPI, HTTPException, WebSocket, WebSocketDisconnect\nfrom pydantic import BaseModel, Field\n\nfrom replay import config\nfrom replay.events import TradeTape\nfrom replay.session import ReplaySession\nfrom replay.clock import summarize\n\napp = FastAPI(title=\"Market Time Machine\")\n\nSESSIONS = {}\nATTACHED = set()\n\nclass Create(BaseModel):\n    symbol: str = \"AAPL\"\n    date: str\n    tag: str = \"fullday\"\n    speed: float = Field(1.0, gt=0)\n    warmup_ms: int = 120_000\n\nclass Speed(BaseModel):\n    speed: float = Field(..., gt=0)\n\nclass Seek(BaseModel):\n    target_timestamp_ms: int\n\ndef get(sid):\n    if sid not in SESSIONS:\n        raise HTTPException(404, f\"no session {sid}\")\n    return SESSIONS[sid]\n\n@app.post(\"\/sessions\")\nasync def create(b: Create):\n    path = config.PROCESSED \/ f\"{b.symbol}_{b.date}_{b.tag}.npz\"\n\n    if not path.exists():\n        raise HTTPException(404, f\"no tape {path.name}\")\n\n    s = ReplaySession(\n        TradeTape.load(path),\n        b.speed,\n        b.warmup_ms\n    )\n\n    SESSIONS[s.id] = s\n    return s.info()\n\n@app.get(\"\/sessions\/{sid}\")\nasync def info(sid: str):\n    return get(sid).info()\n\n@app.get(\"\/sessions\/{sid}\/timing\")\nasync def timing(sid: str):\n    return summarize(get(sid).stats)\n\n@app.post(\"\/sessions\/{sid}\/start\")\nasync def start(sid: str):\n    return await get(sid).start()\n\n@app.post(\"\/sessions\/{sid}\/pause\")\nasync def pause(sid: str):\n    return await get(sid).pause()\n\n@app.post(\"\/sessions\/{sid}\/resume\")\nasync def resume(sid: str):\n    return await get(sid).resume()\n\n@app.post(\"\/sessions\/{sid}\/stop\")\nasync def stop(sid: str):\n    return await get(sid).stop()\n\n@app.post(\"\/sessions\/{sid}\/speed\")\nasync def speed(sid: str, b: Speed):\n    return await get(sid).set_speed(b.speed)\n\n@app.post(\"\/sessions\/{sid}\/seek\")\nasync def seek(sid: str, b: Seek):\n    return await get(sid).seek(b.target_timestamp_ms)\n\n@app.websocket(\"\/sessions\/{sid}\/stream\")\nasync def stream(ws: WebSocket, sid: str):\n    await ws.accept()\n\n    if sid not in SESSIONS:\n        return await ws.close(4004, \"unknown session\")\n\n    if sid in ATTACHED:\n        return await ws.close(4009, \"consumer already attached\")\n\n    ATTACHED.add(sid)\n\n    try:\n        await ws.send_json({\n            \"type\": \"attached\",\n            \"session_id\": sid\n        })\n\n        async for msg in SESSIONS[sid].events():\n            await ws.send_json(msg)\n\n    except (WebSocketDisconnect, Exception):\n        pass\n\n    finally:\n        ATTACHED.discard(sid)\n<\/code><\/pre>\n<p>\u062c\u0628 \u0622\u067e \u0633\u06cc\u0634\u0646 \u0628\u0646\u0627\u062a\u06d2 \u06c1\u06cc\u06ba \u062a\u0648 \u067e\u0631\u0648\u0633\u06cc\u0633 \u0634\u062f\u06c1 \u0645\u0648\u0627\u062f \u0644\u0648\u0688 \u06c1\u0648 \u062c\u0627\u062a\u0627 \u06c1\u06d2\u06d4 <code>.npz<\/code> \u0627\u0633\u06d2 \u0679\u06cc\u067e \u0633\u06d2 \u0644\u067e\u06cc\u0679\u0646\u06d2 \u06a9\u06d2 \u0628\u0639\u062f <code>ReplaySession<\/code>. \u0627\u0633 \u0648\u0642\u062a\u060c API \u06a9\u0648 EODHD \u06a9\u0648 \u06a9\u0627\u0644 \u06a9\u0631\u0646\u06d2 \u06cc\u0627 \u062e\u0627\u0645 JSONL \u062c\u0648\u0627\u0628 \u06a9\u0648 \u062f\u0648\u0628\u0627\u0631\u06c1 \u067e\u0691\u06be\u0646\u06d2 \u06a9\u06cc \u0636\u0631\u0648\u0631\u062a \u0646\u06c1\u06cc\u06ba \u06c1\u06d2\u06d4 \u0639\u0627\u0645 \u0679\u06cc\u067e \u067e\u0631 \u067e\u0644\u06d2 \u0628\u06cc\u06a9 \u0645\u06a9\u0645\u0644 \u0637\u0648\u0631 \u067e\u0631 \u0641\u0639\u0627\u0644 \u06c1\u06d2\u06d4<\/p>\n<p>REST \u06c1\u06cc\u0646\u0688\u0644\u0631\u0632 \u06a9\u0648 \u062c\u0627\u0646 \u0628\u0648\u062c\u06be \u06a9\u0631 \u067e\u062a\u0644\u0627 \u0631\u06a9\u06be\u0627 \u062c\u0627\u062a\u0627 \u06c1\u06d2\u06d4 <code>\/pause<\/code>\u0645\u062b\u0627\u0644 \u06a9\u06d2 \u0637\u0648\u0631 \u067e\u0631\u060c \u0627\u0633 \u0645\u06cc\u06ba \u0627\u067e\u0646\u06cc \u062a\u0648\u0642\u0641 \u06a9\u06cc \u0645\u0646\u0637\u0642 \u0646\u06c1\u06cc\u06ba \u06c1\u06d2\u06d4<\/p>\n<pre><code class=\"language-python\">@app.post(\"\/sessions\/{sid}\/pause\")\nasync def pause(sid: str):\n    return await get(sid).pause()\n<\/code><\/pre>\n<p>\u06cc\u06c1 \u0635\u0631\u0641 \u062d\u06a9\u0645 \u062f\u06cc\u062a\u0627 \u06c1\u06d2. <code>ReplaySession<\/code>. \u06cc\u06c1\u06cc \u067e\u06cc\u0679\u0631\u0646 \u062f\u0648\u0628\u0627\u0631\u06c1 \u0634\u0631\u0648\u0639 \u06a9\u0631\u0646\u06d2\u060c \u0631\u0641\u062a\u0627\u0631 \u06a9\u0648 \u062a\u0628\u062f\u06cc\u0644 \u06a9\u0631\u0646\u06d2\u060c \u062a\u0644\u0627\u0634 \u06a9\u0631\u0646\u06d2 \u0627\u0648\u0631 \u0631\u0648\u06a9\u0646\u06d2 \u067e\u0631 \u0644\u0627\u06af\u0648 \u06c1\u0648\u062a\u0627 \u06c1\u06d2\u06d4 \u06cc\u06c1 \u0627\u0646\u062f\u0631\u0648\u0646\u06cc \u0637\u0648\u0631 \u067e\u0631 \u067e\u0644\u06d2 \u0628\u06cc\u06a9 \u0631\u0648\u06cc\u06d2 \u06a9\u0648 \u0645\u062d\u0641\u0648\u0638 \u0631\u06a9\u06be\u062a\u0627 \u06c1\u06d2\u06d4 <code>replay\/<\/code> \u0641\u0627\u0633\u0679 \u0627\u06d2 \u067e\u06cc \u0622\u0626\u06cc \u06a9\u0648 \u067e\u0627\u0628\u0646\u062f \u06a9\u0631\u0646\u06d2 \u06a9\u06d2 \u0628\u062c\u0627\u0626\u06d2\u06d4<\/p>\n<p>WebSocket \u0627\u06cc\u0646\u0688 \u067e\u0648\u0627\u0626\u0646\u0679 \u062f\u0648\u0633\u0631\u06cc \u0633\u0645\u062a \u06a9\u0648 \u0633\u0646\u0628\u06be\u0627\u0644\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4 \u062c\u0628 \u06a9\u0648\u0626\u06cc \u0635\u0627\u0631\u0641 \u062c\u0691\u062a\u0627 \u06c1\u06d2\u060c \u0633\u0631\u0648\u0631 \u062c\u0648 \u06a9\u0686\u06be \u0628\u06be\u06cc \u0635\u0627\u0631\u0641 \u067e\u06cc\u062f\u0627 \u06a9\u0631\u062a\u0627 \u06c1\u06d2 \u0627\u0633\u06d2 \u0622\u06af\u06d2 \u0628\u06be\u06cc\u062c \u062f\u06cc\u062a\u0627 \u06c1\u06d2\u06d4 <code>session.events()<\/code>:<\/p>\n<pre><code class=\"language-python\">async for msg in SESSIONS[sid].events():\n    await ws.send_json(msg)\n<\/code><\/pre>\n<p>\u06cc\u06c1 \u0627\u06cc\u06a9 \u0639\u0627\u0645 \u0644\u06cc\u0646 \u062f\u06cc\u0646 \u06c1\u0648 \u0633\u06a9\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<pre><code class=\"language-json\">{\n  \"type\": \"trade\",\n  \"symbol\": \"AAPL\",\n  \"timestamp_ms\": 1784122200009,\n  \"price\": 317.46,\n  \"size\": 3,\n  \"sequence\": 61530328,\n  \"source\": \"replay\"\n}\n<\/code><\/pre>\n<p>\u06cc\u0627 \u067e\u0644\u06d2 \u0628\u06cc\u06a9 \u06a9\u0646\u0679\u0631\u0648\u0644 \u067e\u06cc\u063a\u0627\u0645:<\/p>\n<pre><code class=\"language-json\">{\n  \"type\": \"paused\",\n  \"market_ts_ms\": 1784122200009\n}\n<\/code><\/pre>\n<p>\u0646\u06cc\u0648\u06cc\u06af\u06cc\u0634\u0646 \u0628\u0639\u062f \u0645\u06cc\u06ba \u0627\u06cc\u06a9 \u0627\u0648\u0631 \u0627\u06c1\u0645 \u06a9\u0646\u0679\u0631\u0648\u0644 \u0627\u06cc\u0648\u0646\u0679 \u0645\u062a\u0639\u0627\u0631\u0641 \u06a9\u0631\u0627\u062a\u06cc \u06c1\u06d2\u06d4<\/p>\n<pre><code class=\"language-json\">{\n  \"type\": \"replay_reset\",\n  \"reason\": \"seek\",\n  \"target_timestamp_ms\": 1784136600030\n}\n<\/code><\/pre>\n<p>\u0633\u0631\u0648\u0631 \u0641\u06cc \u067e\u0644\u06d2 \u0628\u06cc\u06a9 \u0633\u06cc\u0634\u0646 \u0627\u06cc\u06a9 WebSocket \u0635\u0627\u0631\u0641 \u06a9\u06cc \u0627\u062c\u0627\u0632\u062a \u062f\u06cc\u062a\u0627 \u06c1\u06d2\u06d4 \u0641\u06cc \u0627\u0644\u062d\u0627\u0644\u060c \u0642\u0637\u0627\u0631 \u0645\u06cc\u06ba \u0644\u06af\u0627\u0646\u0627 \u0628\u0631\u0627\u0688\u06a9\u0627\u0633\u0679 \u0633\u0633\u0679\u0645 \u06a9\u06d2 \u0628\u062c\u0627\u0626\u06d2 \u0627\u06cc\u06a9 FIFO \u06c1\u06cc\u0646\u0688 \u0622\u0641 \u06c1\u06d2\u060c \u0644\u06c1\u0630\u0627 \u0627\u06cc\u06a9 \u0633\u06d2 \u0632\u06cc\u0627\u062f\u06c1 \u0635\u0627\u0631\u0641\u06cc\u0646 \u06a9\u0648 \u0627\u06cc\u06a9 \u06c1\u06cc \u0633\u06cc\u0634\u0646 \u0633\u06d2 \u062c\u0648\u0691\u0646\u06d2 \u0633\u06d2 \u0648\u06c1 \u0627\u06cc\u0648\u0646\u0679\u0633 \u06a9\u0648 \u062a\u0642\u0633\u06cc\u0645 \u06a9\u0631\u0646\u06d2 \u06a9\u0627 \u0633\u0628\u0628 \u0628\u0646\u06d2 \u06af\u0627 \u0628\u062c\u0627\u0626\u06d2 \u0627\u0633 \u06a9\u06d2 \u06a9\u06c1 \u06c1\u0631 \u0627\u06cc\u06a9 \u06a9\u0648 \u0645\u06a9\u0645\u0644 \u0633\u0644\u0633\u0644\u06c1 \u0645\u0644\u06d2\u06d4<\/p>\n<h3 id=\"heading-create-apirunpy\">\u0628\u0646\u0627\u0646\u0627 <code>api\/run.py<\/code><\/h3>\n<p>\u062f\u0648\u0633\u0631\u06cc API \u0641\u0627\u0626\u0644 \u0622\u0633\u0627\u0646\u06cc \u0633\u06d2 FastAPI \u0627\u06cc\u067e\u0644\u06cc\u06a9\u06cc\u0634\u0646 \u0686\u0644\u0627\u062a\u06cc \u06c1\u06d2\u06d4<\/p>\n<p>\u0628\u0646\u0627\u0646\u0627 <code>api\/run.py<\/code>:<\/p>\n<pre><code class=\"language-python\">import argparse\nimport uvicorn\n\nfrom api.server import app\n\nif __name__ == \"__main__\":\n    p = argparse.ArgumentParser()\n    p.add_argument(\"--port\", type=int, default=8765)\n    a = p.parse_args()\n\n    uvicorn.run(\n        app,\n        host=\"127.0.0.1\",\n        port=a.port,\n        log_level=\"warning\"\n    )\n<\/code><\/pre>\n<p>\u067e\u0631\u0648\u062c\u06cc\u06a9\u0679 \u0631\u0648\u0679 \u0645\u06cc\u06ba \u0633\u0631\u0648\u0633 \u0634\u0631\u0648\u0639 \u06a9\u0631\u06cc\u06ba\u06d4<\/p>\n<pre><code class=\"language-shell\">python -m api.run --port 8765\n<\/code><\/pre>\n<p>\u067e\u0644\u06d2 \u0628\u06cc\u06a9 \u0627\u0646\u062c\u0646 \u0645\u06cc\u06ba \u0627\u0628 \u0627\u06cc\u06a9 \u0628\u06cc\u0631\u0648\u0646\u06cc \u06a9\u0646\u0679\u0631\u0648\u0644 \u0627\u0646\u0679\u0631\u0641\u06cc\u0633 \u0627\u0648\u0631 WebSocket \u0627\u06cc\u0648\u0646\u0679 \u0627\u0633\u0679\u0631\u06cc\u0645 \u06c1\u06d2\u06d4 \u0627\u06af\u0644\u0627 \u062d\u0635\u06c1 \u0627\u0633 \u0646\u062f\u06cc \u06a9\u06d2 \u062f\u0648\u0633\u0631\u06cc \u0637\u0631\u0641 \u067e\u0631\u0648\u06af\u0631\u0627\u0645 \u06c1\u06d2\u06d4 \u06cc\u0639\u0646\u06cc \u0648\u06c1 \u0635\u0627\u0631\u0641\u06cc\u0646 \u062c\u0648 \u0635\u0631\u0641 \u0627\u0646 \u0648\u0627\u0642\u0639\u0627\u062a \u06a9\u06d2 \u0630\u0631\u06cc\u0639\u06d2 \u0645\u0627\u0631\u06a9\u06cc\u0679 \u0633\u0679\u06cc\u0679\u0633 \u0628\u0646\u0627\u062a\u06d2 \u06c1\u06cc\u06ba \u062c\u0648 \u0627\u0646\u06c1\u06cc\u06ba \u0645\u0648\u0635\u0648\u0644 \u06c1\u0648\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4<\/p>\n<h2 id=\"heading-build-a-stateful-websocket-consumer\">\u0627\u06cc\u06a9 \u0631\u06cc\u0627\u0633\u062a\u06cc WebSocket \u0635\u0627\u0631\u0641 \u0628\u0646\u0627\u0646\u0627<\/h2>\n<p>\u067e\u0644\u06d2 \u0628\u06cc\u06a9 \u0633\u0631\u0648\u0633\u0632 \u0627\u0628 \u062a\u0627\u0631\u06cc\u062e\u06cc \u0644\u06cc\u0646 \u062f\u06cc\u0646 \u06a9\u0648 \u0633\u0679\u0631\u06cc\u0645 \u06a9\u0631 \u0633\u06a9\u062a\u06cc \u06c1\u06cc\u06ba\u060c \u0644\u06cc\u06a9\u0646 \u0627\u0646\u06c1\u06cc\u06ba \u0627\u0628\u06be\u06cc \u0628\u06be\u06cc WebSocket \u06a9\u06d2 \u062f\u0648\u0633\u0631\u06cc \u0637\u0631\u0641 \u0633\u06d2 \u06a9\u0633\u06cc \u0686\u06cc\u0632 \u06a9\u06cc \u0636\u0631\u0648\u0631\u062a \u06c1\u06d2 \u062a\u0627\u06a9\u06c1 \u0648\u06c1 \u0627\u06cc\u06a9 \u062d\u0642\u06cc\u0642\u06cc \u0628\u06c1\u0627\u0648 \u0627\u06cc\u067e\u0644\u06cc \u06a9\u06cc\u0634\u0646 \u06a9\u06cc \u0637\u0631\u062d \u06a9\u0627\u0645 \u06a9\u0631\u06d2\u06d4<\/p>\n<p>\u0635\u0627\u0631\u0641 \u06a9\u0648 \u0631\u06cc\u06a9\u0627\u0631\u0688\u0646\u06af \u0679\u06cc\u067e\u0633 \u06a9\u0648 \u0644\u0648\u0688 \u0646\u06c1\u06cc\u06ba \u06a9\u0631\u0646\u0627 \u0686\u0627\u06c1\u0626\u06d2 \u06cc\u0627 EODHD \u06a9\u0648 \u0628\u0631\u0627\u06c1 \u0631\u0627\u0633\u062a \u06a9\u0627\u0644 \u0646\u06c1\u06cc\u06ba \u06a9\u0631\u0646\u0627 \u0686\u0627\u06c1\u0626\u06d2\u06d4 \u067e\u0644\u06d2 \u0628\u06cc\u06a9 \u0633\u0679\u0631\u06cc\u0645 \u06a9\u06d2 \u0630\u0631\u06cc\u0639\u06d2 \u0622\u0646\u06d2 \u0648\u0627\u0644\u06d2 \u067e\u06cc\u063a\u0627\u0645\u0627\u062a \u0633\u06d2 \u0645\u0627\u0631\u06a9\u06cc\u0679 \u06a9\u0627 \u0627\u06cc\u06a9 \u062c\u0627\u0645\u0639 \u0646\u0642\u0637\u06c1 \u0646\u0638\u0631 \u0622\u0646\u0627 \u0686\u0627\u06c1\u06cc\u06d2\u06d4<\/p>\n<p>\u06c1\u0645 \u0627\u0633\u06d2 \u0627\u0644\u06af \u067e\u06cc\u06a9\u062c \u0645\u06cc\u06ba \u0631\u06a9\u06be\u06cc\u06ba \u06af\u06d2:<\/p>\n<pre><code class=\"language-plaintext\">market-time-machine\/\n\u251c\u2500\u2500 replay\/\n\u2502   \u2514\u2500\u2500 ...\n\u251c\u2500\u2500 api\/\n\u2502   \u2514\u2500\u2500 ...\n\u2514\u2500\u2500 consumer\/\n    \u251c\u2500\u2500 __init__.py\n    \u2514\u2500\u2500 consumer.py\n<\/code><\/pre>\n<p>\u0627\u0633 \u0679\u06cc\u0648\u0679\u0648\u0631\u06cc\u0644 \u0645\u06cc\u06ba\u060c \u0635\u0627\u0631\u0641 \u0628\u0631\u0642\u0631\u0627\u0631 \u0631\u06a9\u06be\u062a\u0627 \u06c1\u06d2:<\/p>\n<ul>\n<li>\n<p>\u062a\u0627\u0632\u06c1 \u062a\u0631\u06cc\u0646 \u0633\u0648\u062f\u06d2<\/p>\n<\/li>\n<li>\n<p>\u062d\u0627\u0644\u06cc\u06c1 \u0622\u062e\u0631\u06cc \u0641\u0631\u0648\u062e\u062a \u06a9\u0648\u0627\u0644\u06cc\u0641\u0627\u0626\u0646\u06af \u0644\u06cc\u0646 \u062f\u06cc\u0646<\/p>\n<\/li>\n<li>\n<p>\u0645\u062c\u0645\u0648\u0639\u06cc \u062d\u062c\u0645<\/p>\n<\/li>\n<li>\n<p>30 \u0633\u06cc\u06a9\u0646\u0688 VWAP<\/p>\n<\/li>\n<li>\n<p>2 \u0645\u0646\u0679 VWAP<\/p>\n<\/li>\n<li>\n<p>\u0637\u0627\u0642 \u0627\u0648\u0631 \u0635\u0641\u0631 \u06a9\u06cc \u0634\u062f\u062a \u06a9\u06d2 \u0641\u06cc\u0635\u062f<\/p>\n<\/li>\n<li>\n<p>\u0633\u0627\u062f\u06c1 <code>SHORT_ABOVE<\/code> \/ <code>SHORT_BELOW<\/code> \u0635\u0648\u0631\u062a \u062d\u0627\u0644<\/p>\n<\/li>\n<\/ul>\n<p>\u0627\u062e\u062a\u062a\u0627\u0645\u06cc \u0631\u06cc\u0627\u0633\u062a \u062a\u062c\u0627\u0631\u062a\u06cc \u062d\u06a9\u0645\u062a \u0639\u0645\u0644\u06cc \u0646\u06c1\u06cc\u06ba \u06c1\u06d2\u06d4 \u06c1\u0645\u06cc\u06ba \u067e\u0644\u06d2 \u0628\u06cc\u06a9 \u06a9\u0646\u0679\u0631\u0648\u0644\u0632 \u06a9\u06cc \u0636\u0631\u0648\u0631\u062a \u06c1\u06d2\u060c \u062e\u0627\u0635 \u0637\u0648\u0631 \u067e\u0631 \u0646\u06cc\u0648\u06cc\u06af\u06cc\u0634\u0646\u060c \u062d\u0642\u06cc\u0642\u06cc \u0645\u0639\u0646\u0648\u06ba \u0645\u06cc\u06ba \u0628\u06cc\u0627\u0646 \u06a9\u0631\u0646\u06d2 \u06a9\u06d2 \u0644\u06cc\u06d2 \u062a\u0627\u06a9\u06c1 \u06c1\u0645 \u0628\u0639\u062f \u0645\u06cc\u06ba \u0627\u0633 \u0628\u0627\u062a \u06a9\u06cc \u062a\u0635\u062f\u06cc\u0642 \u06a9\u0631 \u0633\u06a9\u06cc\u06ba \u06a9\u06c1 \u06c1\u0645 \u0635\u0627\u0631\u0641\u06cc\u0646 \u06a9\u0648 \u0628\u0627\u0632\u0627\u0631\u06cc \u0631\u06cc\u06a9\u0627\u0631\u0688 \u06a9\u06d2 \u0633\u0627\u062a\u06be \u0646\u06c1\u06cc\u06ba \u0686\u06be\u0648\u0691 \u0631\u06c1\u06d2 \u06c1\u06cc\u06ba\u06d4<\/p>\n<h3 id=\"heading-create-consumerconsumerpy\">\u0628\u0646\u0627\u0646\u0627 <code>consumer\/consumer.py<\/code><\/h3>\n<p>\u0628\u0646\u0627\u0646\u0627 <code>consumer\/consumer.py<\/code>:<\/p>\n<pre><code class=\"language-python\">import argparse, asyncio, collections, json\nimport websockets\n\nclass VWAP:\n    def __init__(self, window_ms):\n        self.w = window_ms\n        self.buf = collections.deque()\n        self.pv = 0.0\n        self.vol = 0.0\n\n    def add(self, ts, px, sz):\n        self.buf.append((ts, px, sz))\n        self.pv += px * sz\n        self.vol += sz\n\n        cut = ts - self.w\n\n        while self.buf and self.buf[0][0] < cut:\n            _, p, s = self.buf.popleft()\n            self.pv -= p * s\n            self.vol -= s\n\n        if self.vol <= 0:\n            self.pv = self.vol = 0.0\n\n    @property\n    def value(self):\n        return self.pv \/ self.vol if self.vol > 0 else None\n\n\nclass State:\n    def __init__(self, short_ms=30_000, long_ms=120_000):\n        self.short = VWAP(short_ms)\n        self.long = VWAP(long_ms)\n\n        self.last_trade = None\n        self.last_sale = None\n        self.signal = None\n\n        self.n = 0\n        self.vol = 0\n        self.odd = 0\n        self.zero = 0\n        self.warming = False\n\n    def apply(self, m):\n        ts = m[\"timestamp_ms\"]\n        px = m[\"price\"]\n        sz = m[\"size\"]\n        meta = m[\"metadata\"]\n\n        self.short.add(ts, px, sz)\n        self.long.add(ts, px, sz)\n\n        self.last_trade = px\n\n        if meta[\"last_sale_eligible\"]:\n            self.last_sale = px\n\n        self.n += 1\n        self.vol += sz\n        self.odd += meta[\"odd_lot\"]\n        self.zero += meta[\"zero_size\"]\n\n        s = self.short.value\n        l = self.long.value\n\n        if s is not None and l is not None:\n            self.signal = (\n                \"SHORT_ABOVE\"\n                if s > l\n                else \"SHORT_BELOW\"\n            )\n\n    def line(self):\n        f = lambda v: \"--\" if v is None else f\"{v:.4f}\"\n\n        return (\n            f\"n={self.n:>7,} \"\n            f\"vol={self.vol:>9,} \"\n            f\"trade={f(self.last_trade):>9} \"\n            f\"sale={f(self.last_sale):>9} \"\n            f\"vwap30s={f(self.short.value):>9} \"\n            f\"vwap2m={f(self.long.value):>9} \"\n            f\"sig={self.signal or '--':<11} \"\n            f\"odd={100*self.odd\/max(1,self.n):4.1f}% \"\n            f\"zero={100*self.zero\/max(1,self.n):4.1f}%\"\n        )\n\n\nasync def run(url, every=3000):\n    st = State()\n\n    async with websockets.connect(\n        url,\n        max_size=None\n    ) as ws:\n        print(\"[consumer] connected\", flush=True)\n\n        async for raw in ws:\n            m = json.loads(raw)\n            t = m[\"type\"]\n\n            if t == \"trade\":\n                st.apply(m)\n\n                if not st.warming and st.n % every == 0:\n                    print(\n                        f\"[consumer] {st.line()}\",\n                        flush=True\n                    )\n\n            elif t == \"replay_reset\":\n                print(\n                    f\"[consumer] RESET -> \"\n                    f\"{m['target_timestamp_ms']} \"\n                    f\"({m['warmup_events']} warmup, \"\n                    f\"{m['purged_stale_events']} purged)\",\n                    flush=True\n                )\n\n                st = State()\n                st.warming = True\n\n            elif t == \"warmup_complete\":\n                st.warming = False\n\n                print(\n                    f\"[consumer] WARM DONE {st.line()}\",\n                    flush=True\n                )\n\n            elif t in (\n                \"session_completed\",\n                \"session_stopped\"\n            ):\n                print(\n                    f\"[consumer] {t.upper()} \"\n                    f\"{st.line()}\",\n                    flush=True\n                )\n                break\n\n            else:\n                print(\n                    f\"[consumer] {t}\",\n                    flush=True\n                )\n\n\nif __name__ == \"__main__\":\n    p = argparse.ArgumentParser()\n\n    p.add_argument(\n        \"--url\",\n        required=True\n    )\n\n    p.add_argument(\n        \"--every\",\n        type=int,\n        default=3000\n    )\n\n    a = p.parse_args()\n\n    asyncio.run(\n        run(a.url, a.every)\n    )\n<\/code><\/pre>\n<p>\u0631\u0648\u0644\u0646\u06af VWAP \u0648\u0646\u0688\u0648\u0632 \u0644\u06cc\u0646 \u062f\u06cc\u0646 \u06a9\u06cc \u062a\u0639\u062f\u0627\u062f \u06a9\u06d2 \u0628\u062c\u0627\u0626\u06d2 \u0645\u0627\u0631\u06a9\u06cc\u0679 \u0679\u0627\u0626\u0645 \u0627\u0633\u0679\u06cc\u0645\u067e \u067e\u0631 \u0645\u0628\u0646\u06cc \u06c1\u06cc\u06ba\u06d4 \u062a\u0645\u0627\u0645 \u0622\u0646\u06d2 \u0648\u0627\u0644\u06d2 \u0644\u06cc\u0646 \u062f\u06cc\u0646 \u062f\u0648\u0646\u0648\u06ba \u0648\u0646\u0688\u0648\u0632 \u0645\u06cc\u06ba \u062c\u0627\u062a\u06d2 \u06c1\u06cc\u06ba\u060c \u0627\u0648\u0631 \u067e\u0644\u06d2 \u0628\u06cc\u06a9 \u0648\u0642\u062a \u06a9\u06d2 \u0633\u0627\u062a\u06be 30 \u0633\u06cc\u06a9\u0646\u0688 \u06cc\u0627 2 \u0645\u0646\u0679 \u0633\u06d2 \u0632\u06cc\u0627\u062f\u06c1 \u067e\u0631\u0627\u0646\u06d2 \u0645\u0634\u0627\u06c1\u062f\u0627\u062a \u06a9\u0648 \u06c1\u0679\u0627 \u062f\u06cc\u0627 \u062c\u0627\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<p>\u0644\u06c1\u0630\u0627\u060c \u0635\u0627\u0631\u0641 \u0631\u06cc\u0627\u0633\u062a \u0622\u06c1\u0633\u062a\u06c1 \u0622\u06c1\u0633\u062a\u06c1 \u062a\u0631\u0642\u06cc \u06a9\u0631\u062a\u06cc \u06c1\u06d2.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/umang.pk\/wp-content\/uploads\/2026\/08\/1787822510_787_\u0645\u0627\u0631\u06a9\u06cc\u0679-\u0679\u0627\u0626\u0645-\u0645\u0634\u06cc\u0646-\u0628\u0646\u0627\u0646\u0627-\u0627\u0632\u06af\u0631-\u0627\u0648\u0631-\u0648\u06cc\u0628-\u0633\u0627\u06a9\u0679-\u06a9\u0627-\u0627\u0633\u062a\u0639\u0645\u0627\u0644.png\" alt=\"\u0635\u0627\u0631\u0641 \u06a9\u06cc \u062d\u06cc\u062b\u06cc\u062a \u06a9\u0627 \u0628\u062a\u062f\u0631\u06cc\u062c \u0627\u0631\u062a\u0642\u0627\u0621\" style=\"display:block;margin:0 auto\" width=\"600\" height=\"400\" loading=\"lazy\" title=\"\"><\/p>\n<p>\u0627\u06c1\u0645 \u0628\u0627\u062a \u06cc\u06c1 \u06c1\u06d2 \u06a9\u06c1 \u0627\u0646 \u0645\u06cc\u06ba \u0633\u06d2 \u06a9\u0648\u0626\u06cc \u0628\u06be\u06cc \u0631\u06cc\u0627\u0633\u062a \u0627\u0635\u0644 \u062d\u0627\u0644\u062a \u0633\u06d2 \u0646\u06c1\u06cc\u06ba \u0622\u062a\u06cc\u06d4 <code>TradeTape<\/code>. \u0635\u0627\u0631\u0641 \u0635\u0631\u0641 \u0627\u0646 \u0648\u0627\u0642\u0639\u0627\u062a \u06a9\u06d2 \u0628\u0627\u0631\u06d2 \u0645\u06cc\u06ba \u062c\u0627\u0646\u062a\u0627 \u06c1\u06d2 \u062c\u0648 WebSocket \u0633\u06d2 \u06af\u0632\u0631\u06d2 \u06c1\u06cc\u06ba\u06d4<\/p>\n<p>\u06cc\u06c1 \u06a9\u06be\u06cc\u0644 \u06a9\u06d2 \u0648\u0642\u062a \u06a9\u06d2 \u062f\u0648\u0631\u0627\u0646 \u0635\u0627\u0641 \u0637\u0648\u0631 \u067e\u0631 \u06a9\u0627\u0645 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4 \u0646\u06cc\u0648\u06cc\u06af\u06cc\u0634\u0646 \u0686\u06cc\u0632\u0648\u06ba \u06a9\u0648 \u0645\u0632\u06cc\u062f \u0645\u0634\u06a9\u0644 \u0628\u0646\u0627 \u062f\u06cc\u062a\u0627 \u06c1\u06d2 \u06a9\u06cc\u0648\u0646\u06a9\u06c1 \u0635\u0627\u0631\u0641 \u06a9\u0648 \u0631\u06cc \u0633\u06cc\u0679 \u06a9\u06cc\u06d2 \u0628\u063a\u06cc\u0631 \u067e\u0644\u06d2 \u06a9\u0631\u0633\u0631 \u06a9\u0648 \u0645\u0646\u062a\u0642\u0644 \u06a9\u0631\u0646\u06d2 \u0633\u06d2 \u067e\u0644\u06d2 \u06a9\u0631\u0633\u0631 \u0679\u0631\u06cc\u0688\u0646\u06af \u06a9\u06d2 \u062f\u0646 \u063a\u0644\u0637 \u0645\u0642\u0627\u0645 \u067e\u0631 \u067e\u06be\u0646\u0633 \u062c\u0627\u0626\u06d2 \u06af\u0627\u06d4<\/p>\n<h2 id=\"heading-make-seeking-state-safe\">\u0627\u067e\u0646\u06cc \u0628\u0631\u0627\u0624\u0632\u0646\u06af \u06a9\u0648 \u0645\u062d\u0641\u0648\u0638 \u0631\u06a9\u06be\u06cc\u06ba<\/h2>\n<p>\u0646\u06cc\u0648\u06cc\u06af\u06cc\u0634\u0646 \u0635\u0631\u0641 \u067e\u0644\u06d2 \u06a9\u0631\u0633\u0631 \u06a9\u0648 \u062d\u0631\u06a9\u062a \u062f\u06cc\u0646\u06d2 \u06a9\u0627 \u0645\u0639\u0627\u0645\u0644\u06c1 \u0646\u06c1\u06cc\u06ba \u06c1\u06d2\u06d4 \u0627\u06af\u0631 \u0635\u0627\u0631\u0641 \u067e\u06c1\u0644\u06d2 \u06c1\u06cc \u062a\u062c\u0627\u0631\u062a\u06cc \u062f\u0646 \u0645\u06cc\u06ba \u0627\u06cc\u06a9 \u0645\u0642\u0627\u0645 \u067e\u0631 \u0631\u0648\u0644\u0646\u06af \u0633\u0679\u06cc\u0679 \u0642\u0627\u0626\u0645 \u06a9\u0631 \u0686\u06a9\u0627 \u06c1\u06d2\u060c \u062a\u0648 \u0627\u0633 \u062d\u0627\u0644\u062a \u06a9\u0648 \u0631\u06cc \u0633\u06cc\u0679 \u06a9\u06cc\u06d2 \u0628\u063a\u06cc\u0631 \u06a9\u0633\u06cc \u062f\u0648\u0633\u0631\u06d2 \u0645\u0642\u0627\u0645 \u067e\u0631 \u062c\u0627\u0646\u06d2 \u06a9\u06d2 \u0646\u062a\u06cc\u062c\u06d2 \u0645\u06cc\u06ba \u062f\u0648 \u0645\u062e\u062a\u0644\u0641 \u0645\u0627\u0631\u06a9\u06cc\u0679 \u0631\u06cc\u06a9\u0627\u0631\u0688\u0632 \u06a9\u0627 \u0645\u0631\u06a9\u0628 \u06c1\u0648 \u06af\u0627\u06d4<\/p>\n<p>\u0641\u0631\u0636 \u06a9\u0631\u06cc\u06ba \u06a9\u06c1 \u0635\u0627\u0631\u0641 14:00 \u062a\u06a9 \u067e\u06c1\u0646\u0686 \u062c\u0627\u062a\u0627 \u06c1\u06d2\u06d4 2 \u0645\u0646\u0679 \u0637\u0648\u06cc\u0644 VWAP \u0645\u06cc\u06ba \u062a\u0642\u0631\u06cc\u0628\u0627\u064b 13:58 \u06a9\u06d2 \u0628\u0639\u062f \u0628\u06be\u06cc \u0644\u06cc\u0646 \u062f\u06cc\u0646 \u0634\u0627\u0645\u0644 \u06c1\u06d2\u06d4 \u0628\u0633 \u067e\u0644\u06d2 \u0628\u06cc\u06a9 \u06a9\u0631\u0633\u0631 \u06a9\u0648 13:30 \u067e\u0631 \u0648\u0627\u067e\u0633 \u0644\u06d2 \u062c\u0627\u0626\u06cc\u06ba \u0627\u0648\u0631 \u0679\u0631\u0627\u0646\u0632\u06cc\u06a9\u0634\u0646\u0632 \u06a9\u0648 \u0627\u06cc\u06a9\u0633\u067e\u0648\u0631\u0679 \u06a9\u0631\u0646\u0627 \u062c\u0627\u0631\u06cc \u0631\u06a9\u06be\u06cc\u06ba\u060c \u0627\u0648\u0631 \u0645\u0633\u062a\u0642\u0628\u0644 \u06a9\u06d2 \u0645\u0634\u0627\u06c1\u062f\u0627\u062a \u0645\u06cc\u0645\u0648\u0631\u06cc \u0645\u06cc\u06ba \u0631\u06c1\u06cc\u06ba \u06af\u06d2\u06d4<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/umang.pk\/wp-content\/uploads\/2026\/08\/1787822510_684_\u0645\u0627\u0631\u06a9\u06cc\u0679-\u0679\u0627\u0626\u0645-\u0645\u0634\u06cc\u0646-\u0628\u0646\u0627\u0646\u0627-\u0627\u0632\u06af\u0631-\u0627\u0648\u0631-\u0648\u06cc\u0628-\u0633\u0627\u06a9\u0679-\u06a9\u0627-\u0627\u0633\u062a\u0639\u0645\u0627\u0644.png\" alt=\"\u067e\u0631\u0627\u0646\u0627 \u0627\u0633\u0679\u06cc\u0679\u0633 \u0628\u06af\" style=\"display:block;margin:0 auto\" width=\"600\" height=\"400\" loading=\"lazy\" title=\"\"><\/p>\n<p>\u0644\u06c1\u0630\u0627\u060c \u067e\u0644\u06d2 \u0628\u06cc\u06a9 \u06a9\u0648 \u0646\u06cc\u0686\u06d2 \u06a9\u06cc \u062f\u06be\u0627\u0631\u06d2 \u06a9\u06cc \u062d\u0627\u0644\u062a \u06a9\u0648 \u062f\u0648\u0628\u0627\u0631\u06c1 \u062a\u0631\u062a\u06cc\u0628 \u062f\u06cc\u0646\u0627 \u0686\u0627\u06c1\u06cc\u06d2 \u0627\u0648\u0631 \u0639\u0627\u0645 \u067e\u0644\u06d2 \u0628\u06cc\u06a9 \u06a9\u06d2 \u062c\u0627\u0631\u06cc \u0631\u06c1\u0646\u06d2 \u0633\u06d2 \u067e\u06c1\u0644\u06d2 \u0646\u0626\u06d2 \u0679\u0627\u0626\u0645 \u0627\u0633\u0679\u06cc\u0645\u067e \u06a9\u06cc \u0628\u0646\u06cc\u0627\u062f \u067e\u0631 \u062f\u0648\u0628\u0627\u0631\u06c1 \u062a\u0639\u0645\u06cc\u0631 \u06a9\u0631\u0646\u0627 \u0686\u0627\u06c1\u06cc\u06d2\u06d4<\/p>\n<h3 id=\"heading-reset-and-warm-up-the-consumer\">\u06a9\u0646\u0632\u06cc\u0648\u0645\u0631 \u0631\u06cc \u0633\u06cc\u0679 \u0627\u0648\u0631 \u0648\u0627\u0631\u0645 \u0627\u067e<\/h3>\n<p>\u06a9\u06c1 <code>seek()<\/code> \u06c1\u0645 \u0646\u06d2 \u062c\u0648 \u0637\u0631\u06cc\u0642\u06d2 \u0634\u0627\u0645\u0644 \u06a9\u06cc\u06d2 \u06c1\u06cc\u06ba\u06d4 <code>ReplaySession<\/code> \u06c1\u0645 \u067e\u06c1\u0644\u06d2 \u06c1\u06cc \u0627\u0633 \u062a\u0631\u062a\u06cc\u0628 \u067e\u0631 \u06a9\u0627\u0631\u0631\u0648\u0627\u0626\u06cc \u06a9\u0631 \u0631\u06c1\u06d2 \u06c1\u06cc\u06ba\u06d4 \u0627\u06c1\u0645 \u062d\u0635\u06c1 \u0645\u0648\u062c\u0648\u062f\u06c1 \u067e\u0631\u0648\u0688\u06cc\u0648\u0633\u0631 \u06a9\u0648 \u0631\u0648\u06a9\u0646\u06d2 \u0627\u0648\u0631 \u0679\u06cc\u067e \u067e\u0631 \u0645\u0637\u0644\u0648\u0628\u06c1 \u0645\u0642\u0627\u0645 \u062a\u0644\u0627\u0634 \u06a9\u0631\u0646\u06d2 \u06a9\u06d2 \u0633\u0627\u062a\u06be \u0634\u0631\u0648\u0639 \u06c1\u0648\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<pre><code class=\"language-python\">was = self.state\nawait self._kill()\n\nasync with self._lock:\n    idx = max(\n        0,\n        min(\n            self.tape.index_at(target_ms),\n            len(self.tape)-1\n        )\n    )\n\n    self._epoch += 1\n    self.cursor = idx\n    self.state = State.PAUSED\n    self.clock.pause()\n<\/code><\/pre>\n<p>\u0627\u06af\u0644\u0627\u060c \u0627\u067e\u0646\u06d2 \u0645\u0642\u0635\u062f \u0633\u06d2 2 \u0645\u0646\u0679 \u067e\u06c1\u0644\u06d2 \u0627\u067e\u0646\u06d2 \u062a\u06cc\u0627\u0631 \u067e\u0648\u0627\u0626\u0646\u0679 \u06a9\u0627 \u062d\u0633\u0627\u0628 \u0644\u06af\u0627\u0626\u06cc\u06ba\u06d4<\/p>\n<pre><code class=\"language-python\">warm = max(0, self.tape.index_at(int(self.tape.ts[idx]) - self.warmup_ms))\n<\/code><\/pre>\n<p>\u06c1\u0645 2 \u0645\u0646\u0679 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06a9\u0631\u0646\u06d2 \u06a9\u06cc \u0648\u062c\u06c1 \u06cc\u06c1 \u06c1\u06d2 \u06a9\u06c1 \u06cc\u06c1 \u0635\u0627\u0631\u0641\u06cc\u0646 \u06a9\u06d2 \u0628\u0631\u0642\u0631\u0627\u0631 \u0631\u06a9\u06be\u0646\u06d2 \u0648\u0627\u0644\u06d2 \u0637\u0648\u06cc\u0644 \u062a\u0631\u06cc\u0646 \u0631\u0648\u0644\u0646\u06af \u067e\u06cc\u0631\u06cc\u0688 \u0633\u06d2 \u0645\u06cc\u0644 \u06a9\u06be\u0627\u062a\u0627 \u06c1\u06d2\u06d4 \u0627\u0633 \u0648\u0642\u0641\u06d2 \u06a9\u0648 \u062f\u0648\u0628\u0627\u0631\u06c1 \u0686\u0644\u0627\u0646\u0627 \u0646\u0626\u06cc \u062c\u06af\u06c1 \u067e\u0631 30 \u0633\u06cc\u06a9\u0646\u0688 \u0627\u0648\u0631 2 \u0645\u0646\u0679 \u06a9\u06d2 VWAP \u062f\u0648\u0646\u0648\u06ba \u06a9\u0648 \u062f\u0648\u0628\u0627\u0631\u06c1 \u062a\u0634\u06a9\u06cc\u0644 \u062f\u06cc\u0646\u06d2 \u06a9\u06d2 \u0644\u06cc\u06d2 \u06a9\u0627\u0641\u06cc \u06c1\u06d2\u06d4<\/p>\n<p>\u062a\u06cc\u0627\u0631 \u0679\u0631\u0627\u0646\u0632\u06cc\u06a9\u0634\u0646 \u0628\u06be\u06cc\u062c\u0646\u06d2 \u0633\u06d2 \u067e\u06c1\u0644\u06d2\u060c \u0633\u06cc\u0634\u0646 \u06a9\u06cc \u0642\u0637\u0627\u0631 \u0645\u06cc\u06ba \u0627\u0646\u062a\u0638\u0627\u0631 \u06a9\u0631\u0646\u06d2 \u0648\u0627\u0644\u06d2 \u06a9\u0633\u06cc \u0628\u06be\u06cc \u0628\u0627\u0642\u0627\u0639\u062f\u06c1 \u0644\u06cc\u0646 \u062f\u06cc\u0646 \u06a9\u06d2 \u067e\u06cc\u063a\u0627\u0645\u0627\u062a \u06a9\u0648 \u06c1\u0679\u0627 \u062f\u06cc\u0627 \u062c\u0627\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<pre><code class=\"language-python\">purged = sum(1 for m in self._q if m.get(\"type\") == \"trade\")\nself._q = collections.deque(m for m in self._q if m.get(\"type\") != \"trade\")\n<\/code><\/pre>\n<p>\u0633\u06cc\u0634\u0646 \u067e\u06be\u0631 \u0627\u06cc\u06a9 \u0648\u0627\u0636\u062d \u067e\u06cc\u063a\u0627\u0645 \u0628\u06be\u06cc\u062c\u062a\u0627 \u06c1\u06d2\u06d4 <code>replay_reset<\/code> \u0648\u0627\u0642\u0639\u06c1:<\/p>\n<pre><code class=\"language-python\">self._ctrl(\n    \"replay_reset\",\n    reason=\"seek\",\n    target_timestamp_ms=int(self.tape.ts[idx]),\n    warmup_from_ms=int(self.tape.ts[warm]),\n    warmup_events=idx-warm,\n    purged_stale_events=purged,\n    epoch=self._epoch\n)\n<\/code><\/pre>\n<p>\u0635\u0627\u0631\u0641 \u0645\u0648\u062c\u0648\u062f\u06c1 \u062d\u0627\u0644\u062a \u06a9\u0648 \u062d\u0630\u0641 \u06a9\u0631\u06a9\u06d2 \u062c\u0648\u0627\u0628 \u062f\u06cc\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<pre><code class=\"language-python\">elif t == \"replay_reset\":\n    st = State()\n    st.warming = True\n<\/code><\/pre>\n<p>\u0627\u0628 \u0633\u06cc\u0634\u0646 \u06c1\u062f\u0641 \u0633\u06d2 \u0639\u06cc\u0646 \u067e\u06c1\u0644\u06d2 \u0645\u0627\u0636\u06cc \u06a9\u06d2 \u0644\u06cc\u0646 \u062f\u06cc\u0646 \u06a9\u0648 \u0628\u06be\u06cc\u062c \u0633\u06a9\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<pre><code class=\"language-python\">for k in range(warm, idx):\n    await self._put({\n        **self.tape[k].to_wire(),\n        \"warmup\": True\n    })\n\nself._ctrl(\n    \"warmup_complete\",\n    market_ts_ms=int(self.tape.ts[idx])\n)\n<\/code><\/pre>\n<p>\u06cc\u06c1 \u0644\u06cc\u0646 \u062f\u06cc\u0646 \u0628\u0627\u0644\u06a9\u0644 \u0627\u0633\u06cc \u0637\u0631\u062d \u06a9\u0627\u0645 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4 <code>State.apply()<\/code> \u0645\u0646\u0637\u0642 \u06a9\u0648 \u0627\u06cc\u06a9 \u0639\u0627\u0645 \u0631\u06cc \u067e\u0644\u06d2 \u0627\u06cc\u0648\u0646\u0679 \u0633\u0645\u062c\u06be\u0627 \u062c\u0627\u062a\u0627 \u06c1\u06d2\u060c \u0644\u06cc\u06a9\u0646 \u0635\u0627\u0631\u0641 \u0639\u0627\u0645 \u0622\u0624\u0679 \u067e\u0679 \u06a9\u0648 \u062f\u0628\u0627 \u062f\u06cc\u062a\u0627 \u06c1\u06d2\u06d4 <code>warming<\/code> \u06c1\u06d2 <code>True<\/code>.<\/p>\n<p>\u0644\u06c1\u0630\u0627 \u0645\u062c\u0645\u0648\u0639\u06cc \u0637\u0648\u0631 \u067e\u0631 \u0646\u06cc\u0648\u06cc\u06af\u06cc\u0634\u0646 \u0628\u06c1\u0627\u0624 \u0645\u0646\u062f\u0631\u062c\u06c1 \u0630\u06cc\u0644 \u06c1\u06d2:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/umang.pk\/wp-content\/uploads\/2026\/08\/1787822510_702_\u0645\u0627\u0631\u06a9\u06cc\u0679-\u0679\u0627\u0626\u0645-\u0645\u0634\u06cc\u0646-\u0628\u0646\u0627\u0646\u0627-\u0627\u0632\u06af\u0631-\u0627\u0648\u0631-\u0648\u06cc\u0628-\u0633\u0627\u06a9\u0679-\u06a9\u0627-\u0627\u0633\u062a\u0639\u0645\u0627\u0644.png\" alt=\"\u0628\u06c1\u0627\u0624 \u06a9\u0627 \u067e\u06cc\u0686\u06be\u0627 \u06a9\u0631\u06cc\u06ba\" style=\"display:block;margin:0 auto\" width=\"600\" height=\"400\" loading=\"lazy\" title=\"\"><\/p>\n<h3 id=\"heading-check-the-rebuilt-state\">\u062f\u0648\u0628\u0627\u0631\u06c1 \u062a\u0639\u0645\u06cc\u0631 \u06a9\u06cc \u062d\u06cc\u062b\u06cc\u062a \u06a9\u0648 \u0686\u06cc\u06a9 \u06a9\u0631\u06cc\u06ba\u06d4<\/h3>\n<p>\u0645\u06a9\u0645\u0644 \u0633\u06cc\u0634\u0646 \u0686\u0644\u0627\u0646\u06d2 \u06a9\u06d2 \u0644\u06cc\u06d2\u060c \u0645\u06cc\u06ba \u0646\u06d2 \u067e\u0644\u06d2 \u0628\u06cc\u06a9 \u0645\u0648\u0642\u0648\u0641 \u06a9\u06cc\u0627 \u0627\u0648\u0631 13:30 \u06a9\u0627 \u062a\u0639\u0627\u0642\u0628 \u06a9\u06cc\u0627\u06d4 \u062f\u0631\u062e\u0648\u0627\u0633\u062a \u06a9\u0631\u062f\u06c1 \u0679\u0627\u0626\u0645 \u0627\u0633\u0679\u06cc\u0645\u067e \u067e\u0631 \u06cc\u0627 \u0627\u0633 \u06a9\u06d2 \u0628\u0639\u062f \u067e\u06c1\u0644\u0627 \u0627\u0635\u0644 \u0648\u0627\u0642\u0639\u06c1 \u06cc\u06c1 \u06c1\u06d2: <code>1784136600030<\/code>.<\/p>\n<p>\u0635\u0627\u0631\u0641\u06cc\u0646 \u06a9\u0648 \u0645\u0648\u0635\u0648\u0644 \u06c1\u0648\u0627:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/umang.pk\/wp-content\/uploads\/2026\/08\/1787822510_18_\u0645\u0627\u0631\u06a9\u06cc\u0679-\u0679\u0627\u0626\u0645-\u0645\u0634\u06cc\u0646-\u0628\u0646\u0627\u0646\u0627-\u0627\u0632\u06af\u0631-\u0627\u0648\u0631-\u0648\u06cc\u0628-\u0633\u0627\u06a9\u0679-\u06a9\u0627-\u0627\u0633\u062a\u0639\u0645\u0627\u0644.png\" alt=\"\u0631\u0646\u0646\u06af \u0631\u06cc \u0628\u0644\u0679\" style=\"display:block;margin:0 auto\" width=\"600\" height=\"400\" loading=\"lazy\" title=\"\"><\/p>\n<p>\u0645\u0648\u062c\u0648\u062f\u06c1 \u0635\u0627\u0631\u0641 \u0642\u0648\u0645 \u063a\u0627\u0626\u0628 \u06c1\u0648 \u0686\u06a9\u06cc \u06c1\u06d2\u060c <code>3,456<\/code> \u062a\u0627\u0631\u06cc\u062e\u06cc \u0679\u0631\u06cc\u0688\u0646\u06af \u0645\u06cc\u06ba \u0633\u06cc\u0634\u0646 \u0645\u06cc\u06ba \u0646\u0626\u06d2 \u067e\u0648\u0627\u0626\u0646\u0679\u0633 \u06a9\u06d2 \u0627\u0631\u062f \u06af\u0631\u062f \u062f\u0648 \u0631\u0648\u0644\u0646\u06af VWAP \u0648\u0646\u0688\u0648\u0632 \u06a9\u0648 \u062f\u0648\u0628\u0627\u0631\u06c1 \u062a\u0631\u062a\u06cc\u0628 \u062f\u06cc\u0627 \u06af\u06cc\u0627 \u06c1\u06d2\u06d4 \u0646\u0627\u0631\u0645\u0644 \u0679\u0627\u0626\u0645 \u067e\u0644\u06d2 \u0628\u06cc\u06a9 \u0627\u0628 \u0646\u06cc\u0648\u06cc\u06af\u06cc\u0634\u0646 \u0628\u0627\u0624\u0646\u0688\u0631\u06cc \u0633\u06d2 \u0645\u0627\u0631\u06a9\u06cc\u0679 \u06a9\u06d2 \u062d\u0627\u0644\u0627\u062a \u06a9\u0648 \u06af\u0632\u0631\u06d2 \u0628\u063a\u06cc\u0631 \u062f\u0648\u0628\u0627\u0631\u06c1 \u0634\u0631\u0648\u0639 \u06a9\u06cc\u0627 \u062c\u0627 \u0633\u06a9\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<h2 id=\"heading-replay-the-full-aapl-trading-day\">\u0645\u06a9\u0645\u0644 AAPL \u062a\u062c\u0627\u0631\u062a\u06cc \u062f\u0646 \u062f\u0648\u0628\u0627\u0631\u06c1 \u062f\u06cc\u06a9\u06be\u06cc\u06ba<\/h2>\n<p>\u0627\u0628 \u062a\u0645\u0627\u0645 \u0679\u06a9\u0691\u06d2 \u062c\u0691\u06d2 \u06c1\u0648\u0626\u06d2 \u06c1\u06cc\u06ba\u06d4 \u0641\u0627\u0633\u0679 \u0627\u06d2 \u067e\u06cc \u0622\u0626\u06cc \u06a9\u06d2 \u0630\u0631\u06cc\u0639\u06d2 \u067e\u0648\u0631\u06d2 \u062f\u0646 \u06a9\u06d2 \u0679\u06cc\u067e\u0633 \u06a9\u0648 \u06a9\u0646\u0679\u0631\u0648\u0644 \u06a9\u06cc\u0627 \u062c\u0627 \u0633\u06a9\u062a\u0627 \u06c1\u06d2\u060c \u0627\u0644\u06af \u0627\u0644\u06af \u0635\u0627\u0631\u0641\u06cc\u0646 \u0635\u0631\u0641 \u0648\u06cc\u0628 \u0633\u0627\u06a9\u0679 \u06a9\u06d2 \u0630\u0631\u06cc\u0639\u06d2 \u0644\u06cc\u0646 \u062f\u06cc\u0646 \u0627\u0648\u0631 \u06a9\u0646\u0679\u0631\u0648\u0644 \u0627\u06cc\u0648\u0646\u0679\u0633 \u06a9\u0648 \u062f\u06cc\u06a9\u06be\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4<\/p>\n<p>\u067e\u06c1\u0644\u06d2 \u0679\u0631\u0645\u06cc\u0646\u0644 \u0645\u06cc\u06ba \u067e\u0644\u06d2 \u0628\u06cc\u06a9 \u0633\u0631\u0648\u0633 \u0634\u0631\u0648\u0639 \u06a9\u0631\u06cc\u06ba\u06d4<\/p>\n<pre><code class=\"language-shell\">python -m api.run --port 8765\n<\/code><\/pre>\n<p>\u06c1\u0645\u0627\u0631\u06cc \u0622\u062e\u0631\u06cc \u062f\u0648\u0691 \u06a9\u06d2 \u0644\u06cc\u06d2\u060c \u0622\u0626\u06cc\u06d2 \u0627\u0633 \u06a9\u06d2 \u0633\u0627\u062a\u06be \u0634\u0631\u0648\u0639 \u06a9\u0631\u06cc\u06ba: <code>10x<\/code>\u0645\u0627\u0631\u06a9\u06cc\u0679 \u06a9\u0648 \u0631\u0648\u06a9\u06cc\u06ba \u0627\u0648\u0631 \u0627\u0633 \u067e\u0631 \u0633\u0648\u0626\u0686 \u06a9\u0631\u06cc\u06ba: <code>50x<\/code>\u062f\u0648\u0628\u0627\u0631\u06c1 \u0634\u0631\u0648\u0639 \u06a9\u0631\u06cc\u06ba\u060c \u062f\u0648\u0628\u0627\u0631\u06c1 \u062a\u0648\u0642\u0641 \u06a9\u0631\u06cc\u06ba\u060c 13:30 \u062a\u06a9 \u062a\u0644\u0627\u0634 \u06a9\u0631\u06cc\u06ba\u060c \u0635\u0627\u0631\u0641 \u06a9\u06cc \u062d\u0627\u0644\u062a \u06a9\u0648 \u062f\u0648\u0628\u0627\u0631\u06c1 \u0628\u0646\u0627\u0626\u06cc\u06ba\u060c \u0627\u0648\u0631 \u0622\u062e\u0631 \u06a9\u0627\u0631 \u062e\u062a\u0645 \u06c1\u0648\u0646\u06d2 \u06a9\u06cc \u0637\u0631\u0641 \u062f\u0648\u0691\u06cc\u06ba\u06d4 <code>400x<\/code>.<\/p>\n<h3 id=\"heading-run-the-full-replay\">\u0645\u06a9\u0645\u0644 \u06a9\u06be\u06cc\u0644 \u0686\u0644\u0627\u0626\u06cc\u06ba\u06d4<\/h3>\n<p>\u0639\u0627\u0631\u0636\u06cc \u0637\u0648\u0631 \u067e\u0631 \u062f\u0631\u062c \u0630\u06cc\u0644 \u06a9\u0648 \u0645\u062d\u0641\u0648\u0638 \u06a9\u0631\u06cc\u06ba\u06d4 <code>demo.py<\/code> \u0645\u0646\u0635\u0648\u0628\u06d2 \u06a9\u06cc \u062c\u0691 \u0645\u06cc\u06ba. \u06cc\u06c1 \u0627\u0633\u06a9\u0631\u067e\u0679 \u0635\u0631\u0641 \u0627\u06cc\u06a9 \u0688\u06cc\u0645\u0648 \u0688\u0631\u0627\u0626\u06cc\u0648\u0631 \u06c1\u06d2\u06d4 \u062f\u0648\u0628\u0627\u0631\u06c1 \u067e\u06cc\u062f\u0627 \u06a9\u0631\u0646\u06d2 \u0648\u0627\u0644\u06d2 \u0627\u0646\u062c\u0646 \u0627\u0648\u0631 \u0635\u0627\u0631\u0641\u06cc\u0646 \u0627\u0633 \u067e\u06cc\u06a9\u06cc\u062c \u0645\u06cc\u06ba \u0631\u06c1\u062a\u06d2 \u06c1\u06cc\u06ba \u062c\u0648 \u06c1\u0645 \u0646\u06d2 \u067e\u06c1\u0644\u06d2 \u06c1\u06cc \u0628\u0646\u0627\u06cc\u0627 \u06c1\u06d2\u06d4<\/p>\n<pre><code class=\"language-python\">import asyncio, os, subprocess, sys\nimport httpx\n\nBASE = \"http:\/\/127.0.0.1:8765\"\nROOT = os.getcwd()\nSEEK_1330_MS = 1784136600000\n\nasync def demo():\n    async with httpx.AsyncClient(base_url=BASE, timeout=120) as c:\n        r = await c.post(\"\/sessions\", json={\n            \"symbol\": \"AAPL\",\n            \"date\": \"2026-07-15\",\n            \"tag\": \"fullday\",\n            \"speed\": 10.0\n        })\n\n        sid = r.json()[\"session_id\"]\n\n        consumer = subprocess.Popen([\n            sys.executable,\n            \"-u\",\n            \"-m\",\n            \"consumer.consumer\",\n            \"--url\",\n            f\"ws:\/\/127.0.0.1:8765\/sessions\/{sid}\/stream\",\n            \"--every\",\n            \"25000\"\n        ], cwd=ROOT)\n\n        await asyncio.sleep(1.5)\n\n        controls = [\n            (\"START @10.0x\", f\"\/sessions\/{sid}\/start\", None, 4),\n            (\"PAUSE\", f\"\/sessions\/{sid}\/pause\", None, 1.5),\n            (\n                \"SPEED 50x while paused\",\n                f\"\/sessions\/{sid}\/speed\",\n                {\"speed\": 50.0},\n                0.3\n            ),\n            (\"RESUME\", f\"\/sessions\/{sid}\/resume\", None, 3),\n            (\"PAUSE\", f\"\/sessions\/{sid}\/pause\", None, 1),\n            (\n                \"SEEK 13:30 while paused\",\n                f\"\/sessions\/{sid}\/seek\",\n                {\"target_timestamp_ms\": SEEK_1330_MS},\n                3\n            ),\n            (\n                \"RESUME after seek\",\n                f\"\/sessions\/{sid}\/resume\",\n                None,\n                3\n            ),\n            (\n                \"SPEED 400.0x to the close\",\n                f\"\/sessions\/{sid}\/speed\",\n                {\"speed\": 400.0},\n                2\n            )\n        ]\n\n        for label, path, payload, wait in controls:\n            print(f\"n--- {label} ---\")\n\n            if payload is None:\n                await c.post(path)\n            else:\n                await c.post(path, json=payload)\n\n            await asyncio.sleep(wait)\n\n        for _ in range(600):\n            await asyncio.sleep(1)\n\n            state = (\n                await c.get(f\"\/sessions\/{sid}\")\n            ).json()\n\n            if state[\"state\"] in (\"completed\", \"stopped\"):\n                break\n\n        print(\n            f\"nfinal: {state['state']} \"\n            f\"{state['cursor']:,}\/{state['total_events']:,}\"\n        )\n\n        print(\n            \"timing:\",\n            (\n                await c.get(f\"\/sessions\/{sid}\/timing\")\n            ).json()\n        )\n\n        if consumer.poll() is None:\n            consumer.terminate()\n\nasyncio.run(demo())\n<\/code><\/pre>\n<p>\u0627\u0633\u06d2 \u062f\u0648\u0633\u0631\u06d2 \u0679\u0631\u0645\u06cc\u0646\u0644 \u0645\u06cc\u06ba \u0686\u0644\u0627\u0626\u06cc\u06ba\u06d4<\/p>\n<pre><code class=\"language-shell\">python demo.py\n<\/code><\/pre>\n<p>\u0635\u0627\u0631\u0641 \u0627\u067e\u0646\u06d2 \u0639\u0645\u0644 \u06a9\u06d2 \u0637\u0648\u0631 \u067e\u0631 \u0634\u0631\u0648\u0639 \u06c1\u0648\u062a\u0627 \u06c1\u06d2 \u0627\u0648\u0631 \u067e\u0644\u06d2 \u0628\u06cc\u06a9 \u0634\u0631\u0648\u0639 \u06c1\u0648\u0646\u06d2 \u0633\u06d2 \u067e\u06c1\u0644\u06d2 WebSocket \u0633\u06d2 \u062c\u0691 \u062c\u0627\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<p>\u0627\u0635\u0644 \u062f\u0648\u0691 \u0627\u0633 \u0637\u0631\u062d \u0634\u0631\u0648\u0639 \u06c1\u0648\u0626\u06cc:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/umang.pk\/wp-content\/uploads\/2026\/08\/1787822511_469_\u0645\u0627\u0631\u06a9\u06cc\u0679-\u0679\u0627\u0626\u0645-\u0645\u0634\u06cc\u0646-\u0628\u0646\u0627\u0646\u0627-\u0627\u0632\u06af\u0631-\u0627\u0648\u0631-\u0648\u06cc\u0628-\u0633\u0627\u06a9\u0679-\u06a9\u0627-\u0627\u0633\u062a\u0639\u0645\u0627\u0644.png\" alt=\"\u062d\u062a\u0645\u06cc \u0639\u0645\u0644 \u062f\u0631\u0622\u0645\u062f \u06a9\u0627 \u0627\u0628\u062a\u062f\u0627\u0626\u06cc \u0633\u0644\u0633\u0644\u06c1\" style=\"display:block;margin:0 auto\" width=\"600\" height=\"400\" loading=\"lazy\" title=\"\"><\/p>\n<p>\u06cc\u06c1 \u0622\u067e \u06a9\u0648 \u06a9\u0633\u06cc \u0633\u06cc\u0634\u0646 \u06a9\u0648 \u0631\u0648\u06a9\u0646\u06d2\u060c \u0627\u0633\u06d2 \u0645\u062e\u062a\u0644\u0641 \u0631\u0641\u062a\u0627\u0631 \u0633\u06d2 \u062f\u0648\u0628\u0627\u0631\u06c1 \u0644\u0627\u06a9 \u06a9\u0631\u0646\u06d2 \u0627\u0648\u0631 \u067e\u0644\u06d2 \u0628\u06cc\u06a9 \u06a9\u0648 \u062f\u0648\u0628\u0627\u0631\u06c1 \u0634\u0631\u0648\u0639 \u06a9\u06cc\u06d2 \u0628\u063a\u06cc\u0631 \u062f\u0648\u0628\u0627\u0631\u06c1 \u0634\u0631\u0648\u0639 \u06a9\u0631\u0646\u06d2 \u06a9\u06cc \u0627\u062c\u0627\u0632\u062a \u062f\u06cc\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<p>\u062f\u0631\u062c \u0630\u06cc\u0644 \u06a9\u0645\u0627\u0646\u0688 \u0628\u0631\u0627\u06c1 \u0631\u0627\u0633\u062a 13:30 \u067e\u0631 \u062c\u0627\u062a\u06cc \u06c1\u06d2\u06d4<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/umang.pk\/wp-content\/uploads\/2026\/08\/1787822511_677_\u0645\u0627\u0631\u06a9\u06cc\u0679-\u0679\u0627\u0626\u0645-\u0645\u0634\u06cc\u0646-\u0628\u0646\u0627\u0646\u0627-\u0627\u0632\u06af\u0631-\u0627\u0648\u0631-\u0648\u06cc\u0628-\u0633\u0627\u06a9\u0679-\u06a9\u0627-\u0627\u0633\u062a\u0639\u0645\u0627\u0644.png\" alt=\"\u062d\u062a\u0645\u06cc \u0639\u0645\u0644 \u062f\u0631\u0622\u0645\u062f \u0631\u0648\u06a9 \u062f\u06cc\u06ba\u06d4\" style=\"display:block;margin:0 auto\" width=\"600\" height=\"400\" loading=\"lazy\" title=\"\"><\/p>\n<p>\u06cc\u06c1 \u067e\u0686\u06be\u0644\u06d2 \u062d\u0635\u06d2 \u0633\u06d2 \u0631\u06cc\u0627\u0633\u062a \u06a9\u06d2 \u0644\u06cc\u06d2 \u0645\u062d\u0641\u0648\u0638 \u0646\u06cc\u0648\u06cc\u06af\u06cc\u0634\u0646 \u06c1\u06d2 \u062c\u0648 \u067e\u0648\u0631\u06d2 \u0633\u0633\u0679\u0645 \u0645\u06cc\u06ba \u06c1\u0648\u062a\u0627 \u06c1\u06d2\u06d4 \u0635\u0627\u0631\u0641\u06cc\u0646 \u067e\u0686\u06be\u0644\u06cc \u062d\u0627\u0644\u062a \u06a9\u0648 \u0686\u06be\u0648\u0691 \u062f\u06cc\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4 <code>3,456<\/code> \u06cc\u06c1 \u0648\u0627\u0631\u0645 \u0627\u067e \u0627\u06cc\u0648\u0646\u0679 \u06c1\u0648\u0646\u06d2 \u06a9\u06d2 \u0628\u0639\u062f \u06c1\u06cc \u0645\u0627\u0631\u06a9\u06cc\u0679 \u06a9\u06d2 \u0646\u0626\u06d2 \u0679\u0627\u0626\u0645 \u0627\u0633\u0679\u06cc\u0645\u067e \u0633\u06d2 \u062c\u0627\u0631\u06cc \u0631\u06c1\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<p>\u0627\u0633 \u06a9\u06d2 \u0628\u0639\u062f \u0622\u067e \u0627\u067e\u0646\u06d2 \u0628\u0627\u0642\u06cc \u0633\u06cc\u0634\u0646 \u06a9\u0648 \u062a\u06cc\u0632 \u06a9\u0631 \u0633\u06a9\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/umang.pk\/wp-content\/uploads\/2026\/08\/1787822511_991_\u0645\u0627\u0631\u06a9\u06cc\u0679-\u0679\u0627\u0626\u0645-\u0645\u0634\u06cc\u0646-\u0628\u0646\u0627\u0646\u0627-\u0627\u0632\u06af\u0631-\u0627\u0648\u0631-\u0648\u06cc\u0628-\u0633\u0627\u06a9\u0679-\u06a9\u0627-\u0627\u0633\u062a\u0639\u0645\u0627\u0644.png\" alt=\"\u062d\u062a\u0645\u06cc \u0639\u0645\u0644 \u062f\u0631\u0622\u0645\u062f \u0633\u0679\u0631\u06cc\u0645 \u0627\u06cc\u06a9\u0633\u0644\u0631\u06cc\u0634\u0646\" style=\"display:block;margin:0 auto\" width=\"600\" height=\"400\" loading=\"lazy\" title=\"\"><\/p>\n<p>\u0633\u06cc\u0634\u0646 \u0679\u06cc\u067e \u06a9\u06d2 \u0627\u062e\u062a\u062a\u0627\u0645 \u062a\u06a9 \u067e\u06c1\u0646\u0686\u0646\u06d2 \u062a\u06a9 \u0635\u0627\u0631\u0641 \u0622\u0646\u06d2 \u0648\u0627\u0644\u06d2 \u0648\u0627\u0642\u0639\u0627\u062a \u0633\u06d2 \u0627\u0633\u0679\u06cc\u0679 \u06a9\u0648 \u0627\u067e \u0688\u06cc\u0679 \u06a9\u0631\u062a\u0627 \u0631\u06c1\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/umang.pk\/wp-content\/uploads\/2026\/08\/1787822511_136_\u0645\u0627\u0631\u06a9\u06cc\u0679-\u0679\u0627\u0626\u0645-\u0645\u0634\u06cc\u0646-\u0628\u0646\u0627\u0646\u0627-\u0627\u0632\u06af\u0631-\u0627\u0648\u0631-\u0648\u06cc\u0628-\u0633\u0627\u06a9\u0679-\u06a9\u0627-\u0627\u0633\u062a\u0639\u0645\u0627\u0644.png\" alt=\"\u0641\u0627\u0626\u0646\u0644 \u0631\u0646 \u0645\u06a9\u0645\u0644 \u06c1\u0648 \u06af\u06cc\u0627\u06d4\" style=\"display:block;margin:0 auto\" width=\"600\" height=\"400\" loading=\"lazy\" title=\"\"><\/p>\n<p>\u062f\u0648\u0646\u0648\u06ba \u0634\u0645\u0627\u0631 \u0645\u062e\u062a\u0644\u0641 \u0686\u06cc\u0632\u0648\u06ba \u06a9\u0648 \u0628\u06cc\u0627\u0646 \u06a9\u0631\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4 \u0633\u06cc\u0634\u0646 \u06a9\u0627 \u06a9\u0631\u0633\u0631 \u0627\u0633 \u067e\u0631 \u062e\u062a\u0645 \u06c1\u0648\u062a\u0627 \u06c1\u06d2: <code>1,032,409\/1,032,409<\/code>\u0627\u0633 \u06a9\u0627 \u0645\u0637\u0644\u0628 \u06c1\u06d2 \u06a9\u06c1 \u06c1\u0645 \u0627\u06cc\u06a9 \u0679\u06cc\u067e \u06a9\u06d2 \u0627\u062e\u062a\u062a\u0627\u0645 \u067e\u0631 \u067e\u06c1\u0646\u0686 \u06af\u0626\u06d2 \u06c1\u06cc\u06ba \u062c\u0648 \u0633\u0627\u0631\u0627 \u062f\u0646 \u0631\u06c1\u062a\u0627 \u06c1\u06d2\u06d4 \u0635\u0627\u0631\u0641\u06cc\u0646 \u06a9\u06cc \u0631\u067e\u0648\u0631\u0679 <code>306,343<\/code> \u0627\u0633 \u06a9\u06cc \u0648\u062c\u06c1 \u06cc\u06c1 \u06c1\u06d2 \u06a9\u06c1 \u0646\u06cc\u0648\u06cc\u06af\u06cc\u0634\u0646 \u06a9\u06d2 \u062f\u0648\u0631\u0627\u0646\u060c \u0627\u0633 \u062d\u0627\u0644\u062a \u06a9\u0648 \u0627\u06cc\u06a9 \u0646\u0626\u06d2 \u0645\u0642\u0627\u0645 \u0633\u06d2 \u0635\u0627\u0641 \u0627\u0648\u0631 \u062f\u0648\u0628\u0627\u0631\u06c1 \u0628\u0646\u0627\u06cc\u0627 \u062c\u0627\u062a\u0627 \u06c1\u06d2\u06d4 \u0627\u06cc\u06a9\u0633\u067e\u0644\u0648\u0631\u06cc\u0634\u0646 \u0631\u06cc\u0626\u0644 \u0679\u0627\u0626\u0645 \u0645\u06cc\u06ba \u0686\u06be\u0648\u0691\u06d2 \u06af\u0626\u06d2 \u062a\u0645\u0627\u0645 \u0644\u06cc\u0646 \u062f\u06cc\u0646 \u06a9\u0648 \u0627\u0633\u0679\u0631\u06cc\u0645 \u06a9\u0631\u0646\u06d2 \u06a9\u06d2 \u0628\u062c\u0627\u0626\u06d2 \u062a\u0627\u0631\u06cc\u062e\u06cc \u0679\u06cc\u067e \u06a9\u06d2 \u06a9\u0686\u06be \u062d\u0635\u0648\u06ba \u067e\u0631 \u0686\u06be\u0644\u0627\u0646\u06af \u0644\u06af\u0627\u062a\u06cc \u06c1\u06d2\u06d4<\/p>\n<p><code>realized_speed<\/code>    \u0627\u0633\u06d2 \u0627\u0633 \u0631\u0646 \u0645\u06cc\u06ba \u062c\u0627\u0646 \u0628\u0648\u062c\u06be \u06a9\u0631 \u0628\u063a\u06cc\u0631 \u0633\u06cc\u0679 \u06a9\u06cc\u0627 \u06af\u06cc\u0627 \u062a\u06be\u0627\u060c \u06a9\u06cc\u0648\u0646\u06a9\u06c1 \u067e\u0644\u06d2 \u0628\u06cc\u06a9 \u06a9\u0648 \u06a9\u0626\u06cc \u0628\u0627\u0631 \u062a\u0648\u0642\u0641\u060c \u0631\u0641\u062a\u0627\u0631 \u0645\u06cc\u06ba \u062a\u0628\u062f\u06cc\u0644\u06cc \u0627\u0648\u0631 \u062a\u0644\u0627\u0634 \u06a9\u0631\u0646\u06d2 \u06a9\u06cc \u0648\u062c\u06c1 \u0633\u06d2 \u062f\u0648\u0628\u0627\u0631\u06c1 \u0645\u0646\u062c\u0645\u062f \u06a9\u06cc\u0627 \u06af\u06cc\u0627 \u062a\u06be\u0627\u06d4 \u0627\u06cc\u06a9 \u0648\u0627\u062d\u062f \u0627\u062e\u062a\u062a\u0627\u0645 \u0633\u06d2 \u0622\u062e\u0631 \u062a\u06a9 \u0631\u0641\u062a\u0627\u0631 \u06a9\u0627 \u062a\u0646\u0627\u0633\u0628 \u0645\u0639\u0646\u06cc \u062e\u06cc\u0632 \u0637\u0648\u0631 \u067e\u0631 \u0627\u0646 \u0633\u06cc\u0634\u0646\u0632 \u06a9\u0627 \u062d\u0633\u0627\u0628 \u0646\u06c1\u06cc\u06ba \u0631\u06a9\u06be\u062a\u0627 \u06c1\u06d2 \u062c\u0648 \u062c\u0627\u0646 \u0628\u0648\u062c\u06be \u06a9\u0631 \u0627\u067e\u0646\u06cc \u06af\u06be\u0691\u06cc\u0648\u06ba \u06a9\u0648 \u062f\u0631\u0645\u06cc\u0627\u0646\u06cc \u0633\u0644\u0633\u0644\u06c1 \u0645\u06cc\u06ba \u062a\u0628\u062f\u06cc\u0644 \u06a9\u0631\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4<\/p>\n<p>\u06cc\u06c1\u0627\u06ba \u062c\u0648 \u0686\u06cc\u0632 \u0627\u06c1\u0645 \u06c1\u06d2 \u0648\u06c1 \u06cc\u06c1 \u06c1\u06d2 \u06a9\u06c1 \u0648\u06c1\u06cc \u0631\u06cc\u06a9\u0627\u0631\u0688 \u0634\u062f\u06c1 \u0679\u06cc\u067e \u067e\u0648\u0631\u06d2 \u06a9\u0646\u0679\u0631\u0648\u0644 \u06a9\u06d2 \u0633\u0644\u0633\u0644\u06d2 \u0645\u06cc\u06ba \u0632\u0646\u062f\u06c1 \u0631\u06c1\u062a\u06cc \u06c1\u06d2\u060c \u0635\u0627\u0631\u0641 \u0628\u0627\u0632\u06cc\u0627\u0641\u062a \u06a9\u06d2 \u0628\u0639\u062f \u0627\u067e\u0646\u06cc \u062d\u0627\u0644\u062a \u06a9\u0648 \u062f\u0648\u0628\u0627\u0631\u06c1 \u062a\u0634\u06a9\u06cc\u0644 \u062f\u06cc\u062a\u0627 \u06c1\u06d2\u060c \u0627\u0648\u0631 \u067e\u0644\u06d2 \u0628\u06cc\u06a9 \u0633\u06cc\u0634\u0646 \u06a9\u06d2 \u062e\u062a\u0645 \u06c1\u0648\u0646\u06d2 \u062a\u06a9 \u062c\u0627\u0631\u06cc \u0631\u06c1\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<h2 id=\"heading-test-the-replay-engine\">\u0631\u06cc \u067e\u0644\u06d2 \u0627\u0646\u062c\u0646 \u0679\u06cc\u0633\u0679<\/h2>\n<p>\u0627\u0633\u06d2 \u0633\u0627\u0631\u0627 \u062f\u0646 \u0686\u0644\u0627\u0646\u06d2 \u0633\u06d2 \u06cc\u06c1 \u0638\u0627\u06c1\u0631 \u06c1\u0648\u06af\u0627 \u06a9\u06c1 \u0633\u0633\u0679\u0645 \u067e\u0648\u0631\u06d2 \u06a9\u0646\u0679\u0631\u0648\u0644 \u06a9\u06d2 \u0633\u0644\u0633\u0644\u06d2 \u0633\u06d2 \u06af\u0632\u0631\u0646\u06d2 \u06a9\u06d2 \u0642\u0627\u0628\u0644 \u06c1\u06d2\u060c \u0644\u06cc\u06a9\u0646 \u0627\u06a9\u06cc\u0644\u06d2 \u0679\u0631\u0645\u06cc\u0646\u0644 \u0622\u0624\u0679 \u067e\u0679 \u0622\u067e \u06a9\u0648 \u06cc\u06c1 \u0646\u06c1\u06cc\u06ba \u0628\u062a\u0627\u0626\u06d2 \u06af\u0627 \u06a9\u06c1 \u0622\u06cc\u0627 \u067e\u0644\u06d2 \u0628\u06cc\u06a9 \u062a\u0631\u062a\u06cc\u0628 \u0645\u06cc\u06ba \u0631\u06c1\u0627\u060c \u062a\u0648\u0642\u0641 \u06a9\u06cc \u062d\u062f\u0648\u062f \u06a9\u0627 \u0645\u0634\u0627\u06c1\u062f\u06c1 \u06a9\u06cc\u0627\u060c \u06cc\u0627 \u0646\u06cc\u0648\u06cc\u06af\u06cc\u0634\u0646 \u06a9\u06d2 \u0628\u0639\u062f \u062f\u0631\u0633\u062a \u062d\u0627\u0644\u062a \u06a9\u0648 \u062f\u0648\u0628\u0627\u0631\u06c1 \u0642\u0627\u0626\u0645 \u06a9\u06cc\u0627\u06d4<\/p>\n<p>\u06c1\u0645 \u0627\u0633 \u0631\u0648\u06cc\u06d2 \u06a9\u06cc \u062c\u0627\u0646\u0686 \u0686\u06be\u0648\u0679\u06d2 \u067e\u06cc\u0645\u0627\u0646\u06d2 \u067e\u0631 \u06a9\u0631\u06cc\u06ba \u06af\u06d2\u06d4 <code>quiet15m<\/code> \u067e\u06c1\u0644\u06d2 \u0628\u0646\u0627\u0626\u06d2 \u06af\u0626\u06d2 \u0679\u06cc\u067e:<\/p>\n<pre><code class=\"language-python\">market-time-machine\/\n\u2514\u2500\u2500 tests\/\n    \u251c\u2500\u2500 __init__.py\n    \u251c\u2500\u2500 conftest.py\n    \u2514\u2500\u2500 test_replay.py\n<\/code><\/pre>\n<p>\u0679\u06cc\u0633\u0679 \u0633\u0648\u0679 \u0686\u0627\u0631 \u0634\u0639\u0628\u0648\u06ba \u067e\u0631 \u0645\u062d\u06cc\u0637 \u06c1\u06d2: \u0627\u06cc\u0648\u0646\u0679 \u06a9\u06cc \u062a\u0631\u062a\u06cc\u0628\u060c \u067e\u0644\u06d2 \u0628\u06cc\u06a9 \u0679\u0627\u0626\u0645\u0646\u06af\u060c \u0645\u0648\u0642\u0648\u0641\/\u062f\u0648\u0628\u0627\u0631\u06c1 \u0634\u0631\u0648\u0639 \u06a9\u0631\u0646\u06d2 \u06a9\u0627 \u0628\u0631\u062a\u0627\u0624\u060c \u0627\u0648\u0631 \u0628\u0627\u0632\u06cc\u0627\u0641\u062a \u06a9\u06d2 \u0628\u0639\u062f \u0631\u06cc\u0627\u0633\u062a \u06a9\u06cc \u062a\u0639\u0645\u06cc\u0631 \u0646\u0648\u06d4<\/p>\n<h3 id=\"heading-create-teststestreplaypy\">\u0628\u0646\u0627\u0646\u0627 <code>tests\/test_replay.py<\/code><\/h3>\n<p>\u0628\u0646\u0627\u0646\u0627 <code>tests\/test_replay.py<\/code>:<\/p>\n<pre><code class=\"language-python\">import asyncio\nimport numpy as np\nimport pytest\n\nfrom replay import config\nfrom replay.events import TradeTape\nfrom replay.session import ReplaySession\nfrom replay.clock import ReplayClock, replay_batches, new_stats, summarize\n\nTAPE = sorted(config.PROCESSED.glob(\"*_quiet15m.npz\"))[0]\n\n@pytest.fixture\ndef tape():\n    return TradeTape.load(TAPE)\n\nasync def collect(sess, seconds):\n    out = []\n\n    async def drain():\n        async for m in sess.events():\n            out.append(m)\n\n    t = asyncio.create_task(drain())\n    await asyncio.sleep(seconds)\n    return out, t\n\n\n@pytest.mark.asyncio\nasync def test_ordering(tape):\n    s = ReplaySession(tape, speed=500)\n    out, t = await collect(s, 0.1)\n\n    await s.start()\n    await asyncio.sleep(2)\n    await s.stop()\n    t.cancel()\n\n    trades = [\n        m for m in out\n        if m[\"type\"] == \"trade\"\n    ]\n\n    assert len(trades) > 1000\n\n    keys = [\n        (m[\"timestamp_ms\"], m[\"sequence\"])\n        for m in trades\n    ]\n\n    assert keys == sorted(keys)\n    assert len(set(keys)) == len(keys)\n\n\n@pytest.mark.asyncio\n@pytest.mark.parametrize(\"speed\", [10, 50, 100])\nasync def test_timing(tape, speed):\n    end = int(\n        np.searchsorted(\n            tape.ts,\n            tape.ts[0] + 60_000,\n            side=\"right\"\n        )\n    )\n\n    clock = ReplayClock(tape.ts[0], speed).start()\n    st = new_stats(speed)\n\n    async for i, j in replay_batches(tape, clock, 0, st):\n        if j >= end:\n            break\n\n    r = summarize(st)\n\n    assert abs(r[\"speed_error_pct\"]) < 5\n    assert r[\"lateness_p95_ms\"] < 50\n\n\n@pytest.mark.asyncio\nasync def test_pause_resume(tape):\n    s = ReplaySession(tape, speed=100)\n    out, t = await collect(s, 0.05)\n\n    await s.start()\n    await asyncio.sleep(1)\n\n    await s.pause()\n\n    n = len([\n        m for m in out\n        if m[\"type\"] == \"trade\"\n    ])\n\n    await asyncio.sleep(1)\n\n    assert len([\n        m for m in out\n        if m[\"type\"] == \"trade\"\n    ]) == n\n\n    await s.resume()\n    await asyncio.sleep(1)\n\n    await s.stop()\n    t.cancel()\n\n    seqs = [\n        m[\"sequence\"]\n        for m in out\n        if m[\"type\"] == \"trade\"\n    ]\n\n    assert seqs == sorted(seqs)\n    assert len(set(seqs)) == len(seqs)\n\n\n@pytest.mark.asyncio\nasync def test_pause_seek_resume(tape):\n    s = ReplaySession(\n        tape,\n        speed=200,\n        warmup_ms=120_000\n    )\n\n    out, t = await collect(s, 0.05)\n\n    await s.start()\n    await asyncio.sleep(0.5)\n    await s.pause()\n\n    target = int(tape.ts[0]) + 300_000\n    await s.seek(target)\n\n    assert s.info()[\"state\"] == \"paused\"\n\n    def past():\n        return [\n            m for m in out\n            if m[\"type\"] == \"trade\"\n            and not m.get(\"warmup\")\n            and m[\"timestamp_ms\"] >= target\n        ]\n\n    await asyncio.sleep(0.4)\n    assert not past()\n\n    await s.resume()\n    await asyncio.sleep(1)\n\n    got = past()\n\n    await s.stop()\n    t.cancel()\n\n    assert got\n\n    seqs = [m[\"sequence\"] for m in got]\n\n    assert seqs == sorted(seqs)\n    assert len(set(seqs)) == len(seqs)\n\n\n@pytest.mark.asyncio\nasync def test_seek_state_equivalence(tape):\n    import sys\n\n    sys.path.insert(0, str(config.ROOT))\n    from consumer.consumer import State as ConsumerState\n\n    s = ReplaySession(\n        tape,\n        speed=200,\n        warmup_ms=120_000\n    )\n\n    live = ConsumerState()\n    reset = None\n    snap = None\n    out = []\n\n    async def drain():\n        nonlocal live, reset, snap\n\n        async for m in s.events():\n            out.append(m)\n\n            if m[\"type\"] == \"trade\":\n                live.apply(m)\n\n            elif m[\"type\"] == \"replay_reset\":\n                reset = m\n                live = ConsumerState()\n\n            elif m[\"type\"] == \"warmup_complete\":\n                snap = (\n                    live.n,\n                    live.vol,\n                    live.short.value,\n                    live.long.value\n                )\n\n    t = asyncio.create_task(drain())\n\n    await s.start()\n    await asyncio.sleep(1)\n\n    await s.seek(\n        int(tape.ts[0]) + 600_000\n    )\n\n    for _ in range(100):\n        if snap:\n            break\n        await asyncio.sleep(0.05)\n\n    await s.stop()\n    t.cancel()\n\n    assert snap\n\n    fresh = ConsumerState()\n\n    lo = tape.index_at(\n        reset[\"warmup_from_ms\"]\n    )\n\n    hi = tape.index_at(\n        reset[\"target_timestamp_ms\"]\n    )\n\n    for k in range(lo, hi):\n        fresh.apply(tape[k].to_wire())\n\n    n, vol, short, long = snap\n\n    assert n == fresh.n == reset[\"warmup_events\"]\n    assert vol == fresh.vol\n\n    assert short == pytest.approx(\n        fresh.short.value,\n        rel=1e-12\n    )\n\n    assert long == pytest.approx(\n        fresh.long.value,\n        rel=1e-12\n    )\n\n    kinds = [m[\"type\"] for m in out]\n\n    seg = out[\n        kinds.index(\"replay_reset\") + 1:\n        kinds.index(\"warmup_complete\")\n    ]\n\n    assert not [\n        m for m in seg\n        if m[\"type\"] == \"trade\"\n        and not m.get(\"warmup\")\n    ]\n<\/code><\/pre>\n<p><code>test_ordering()<\/code>    \u0627\u0633 \u0628\u0627\u062a \u06a9\u06cc \u062a\u0648\u062b\u06cc\u0642 \u06a9\u0631\u06cc\u06ba \u06a9\u06c1 \u0628\u0631\u0622\u0645\u062f \u0634\u062f\u06c1 \u0644\u06cc\u0646 \u062f\u06cc\u0646 \u0627\u0633 \u0637\u0631\u062d \u062a\u0631\u062a\u06cc\u0628 \u062f\u06cc\u06d2 \u06af\u0626\u06d2 \u06c1\u06cc\u06ba: <code>(timestamp, sequence)<\/code> \u0627\u0648\u0631 \u0627\u06cc\u06a9 \u06c1\u06cc \u0648\u0627\u0642\u0639\u06c1 \u062f\u0648 \u0628\u0627\u0631 \u0646\u06c1\u06cc\u06ba \u06c1\u0648\u062a\u0627\u06d4<\/p>\n<p>\u0679\u0627\u0626\u0645\u0646\u06af \u0679\u06cc\u0633\u0679 \u062a\u0627\u0631\u06cc\u062e\u06cc \u0645\u0627\u0631\u06a9\u06cc\u0679 \u0679\u0627\u0626\u0645 \u06a9\u06d2 60 \u0633\u06cc\u06a9\u0646\u0688 \u062a\u06a9 \u0686\u0644\u062a\u0627 \u06c1\u06d2\u06d4 <code>10x<\/code>, <code>50x<\/code>\u0627\u0648\u0631 <code>100x<\/code>. \u0627\u06cc\u0648\u0646\u0679 \u0644\u0648\u067e \u0633\u06d2 \u0633\u062e\u062a \u0631\u06cc\u0626\u0644 \u0679\u0627\u0626\u0645 \u0634\u06cc\u0688\u0648\u0644\u0631 \u06a9\u06cc \u0637\u0631\u062d \u0628\u0631\u062a\u0627\u0624 \u06a9\u0631\u0646\u06d2 \u06a9\u06cc \u062a\u0648\u0642\u0639 \u06a9\u0631\u0646\u06d2 \u06a9\u06d2 \u0628\u062c\u0627\u0626\u06d2\u060c \u06c1\u0645 \u062a\u06be\u0648\u0691\u06cc \u0633\u06cc \u0631\u0648\u0627\u062f\u0627\u0631\u06cc \u06a9\u06cc \u0627\u062c\u0627\u0632\u062a \u062f\u06cc\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4 \u06cc\u0639\u0646\u06cc\u060c \u0648\u0635\u0648\u0644\u06cc \u06a9\u06cc \u0631\u0641\u062a\u0627\u0631 \u06c1\u062f\u0641 \u06a9\u06d2 5% \u06a9\u06d2 \u0627\u0646\u062f\u0631 \u0631\u06c1\u0646\u06cc \u0686\u0627\u06c1\u06cc\u06d2\u060c \u0627\u0648\u0631 95\u0648\u06cc\u06ba \u067e\u0631\u0633\u0646\u0679\u0627\u0626\u0644 \u062a\u0627\u062e\u06cc\u0631 50 ms \u0633\u06d2 \u06a9\u0645 \u0631\u06c1\u0646\u06cc \u0686\u0627\u06c1\u06cc\u06d2\u06d4<\/p>\n<p><code>test_pause_resume()<\/code>    \u06a9\u0686\u06be \u0645\u062e\u062a\u0644\u0641 \u06a9\u06d2 \u0644\u06cc\u06d2 \u0686\u06cc\u06a9 \u06a9\u0631\u06cc\u06ba\u06d4 \u0627\u06cc\u06a9 \u0628\u0627\u0631 <code>pause()<\/code> \u0627\u06cc\u06a9 \u0628\u0627\u0631 \u0648\u0627\u067e\u0633 \u0622\u0646\u06d2 \u06a9\u06d2 \u0628\u0639\u062f\u060c \u067e\u0644\u06d2 \u0628\u06cc\u06a9 \u062f\u0648\u0628\u0627\u0631\u06c1 \u0634\u0631\u0648\u0639 \u06c1\u0648\u0646\u06d2 \u062a\u06a9 \u0645\u0648\u0635\u0648\u0644 \u06c1\u0648\u0646\u06d2 \u0648\u0627\u0644\u06cc \u0644\u06cc\u0646 \u062f\u06cc\u0646 \u06a9\u06cc \u062a\u0639\u062f\u0627\u062f \u0645\u06cc\u06ba \u06a9\u0648\u0626\u06cc \u062a\u0628\u062f\u06cc\u0644\u06cc \u0646\u06c1\u06cc\u06ba \u06c1\u0648\u0646\u06cc \u0686\u0627\u06c1\u06cc\u06d2\u06d4 \u062f\u0648\u0628\u0627\u0631\u06c1 \u0634\u0631\u0648\u0639 \u06a9\u0631\u0646\u06d2 \u06a9\u06d2 \u0628\u0639\u062f\u060c \u0646\u062a\u06cc\u062c\u06d2 \u0645\u06cc\u06ba \u062a\u0631\u062a\u06cc\u0628 \u06a9\u0648 \u0633\u06cc\u062f\u06be \u0645\u06cc\u06ba \u0631\u06a9\u06be\u0646\u0627 \u062c\u0627\u0631\u06cc \u0631\u06a9\u06be\u0646\u0627 \u0686\u0627\u06c1\u06cc\u06d2 \u0627\u0648\u0631 \u0627\u0633 \u0645\u06cc\u06ba \u06a9\u0648\u0626\u06cc \u0688\u067e\u0644\u06cc\u06a9\u06cc\u0679 \u0646\u06c1\u06cc\u06ba \u06c1\u0648\u0646\u0627 \u0686\u0627\u06c1\u06cc\u06d2\u06d4<\/p>\n<p><code>test_pause_seek_resume()<\/code>    \u0645\u06a9\u0645\u0644 \u067e\u0644\u06d2 \u0628\u06cc\u06a9 \u06a9\u06d2 \u0644\u06cc\u06d2 \u0627\u0633\u062a\u0639\u0645\u0627\u0644 \u06c1\u0648\u0646\u06d2 \u0648\u0627\u0644\u06d2 \u0639\u06cc\u0646 \u06a9\u0646\u0679\u0631\u0648\u0644 \u067e\u06cc\u0679\u0631\u0646 \u06a9\u0627 \u0627\u062d\u0627\u0637\u06c1 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4 \u0633\u06cc\u0634\u0646 \u0645\u0648\u0642\u0648\u0641 \u06c1\u0648 \u062c\u0627\u0626\u06d2 \u06af\u0627\u060c 5 \u0645\u0646\u0679 \u06a9\u06d2 \u0644\u06cc\u06d2 \u0679\u06cc\u067e \u067e\u0631 \u062c\u0627\u0626\u06d2 \u06af\u0627\u060c \u0646\u0626\u06cc \u062c\u06af\u06c1 \u067e\u0631 \u0645\u0648\u0642\u0648\u0641 \u0631\u06c1\u06d2 \u06af\u0627\u060c \u0627\u0648\u0631 \u062a\u0628 \u06c1\u06cc \u0639\u0627\u0645 \u0646\u06cc\u0648\u06cc\u06af\u06cc\u0634\u0646 \u06a9\u06d2 \u0628\u0639\u062f \u0644\u06cc\u0646 \u062f\u06cc\u0646 \u062c\u0627\u0631\u06cc \u06a9\u0631\u0646\u0627 \u0634\u0631\u0648\u0639 \u06a9\u0631 \u062f\u06d2 \u06af\u0627\u06d4 <code>resume()<\/code>.<\/p>\n<h3 id=\"heading-verify-state-reconstruction-independently\">\u0622\u0632\u0627\u062f\u0627\u0646\u06c1 \u0637\u0648\u0631 \u067e\u0631 \u0631\u06cc\u0627\u0633\u062a \u06a9\u06cc \u062a\u0639\u0645\u06cc\u0631 \u0646\u0648 \u06a9\u06cc \u062a\u0635\u062f\u06cc\u0642 \u06a9\u0631\u06cc\u06ba\u06d4<\/h3>\n<p>\u0633\u0628 \u0633\u06d2 \u0637\u0627\u0642\u062a\u0648\u0631 \u0627\u0645\u062a\u062d\u0627\u0646 \u06c1\u06d2\u06d4 <code>test_seek_state_equivalence()<\/code>.<\/p>\n<p>\u062c\u0628 \u067e\u0644\u06d2 \u0628\u06cc\u06a9 \u06a9\u0627 \u067e\u062a\u06c1 \u0686\u0644\u062a\u0627 \u06c1\u06d2\u060c \u0635\u0627\u0631\u0641 \u06a9\u0648 \u0627\u06cc\u06a9 \u0631\u06cc \u0633\u06cc\u0679 \u0645\u0644\u062a\u0627 \u06c1\u06d2 \u0627\u0648\u0631 \u067e\u06be\u0631 \u062f\u0648 \u0645\u0646\u0679 \u06a9\u0627 \u0648\u0627\u0631\u0645 \u0627\u067e \u0627\u06cc\u0648\u0646\u0679 \u0645\u0644\u062a\u0627 \u06c1\u06d2\u06d4 \u0645\u062d\u0636 \u062c\u0627\u0646\u0686 \u067e\u0691\u062a\u0627\u0644 \u06a9\u06d2 \u0628\u062c\u0627\u0626\u06d2 <code>warmup_complete<\/code> \u0627\u0634\u0627\u0631\u06c1 \u06a9\u0631\u0646\u06d2 \u067e\u0631\u060c \u06cc\u06c1 \u0679\u06cc\u0633\u0679 \u0628\u0627\u0644\u06a9\u0644 \u0646\u06cc\u0627 \u0679\u06cc\u0633\u0679 \u06c1\u06d2\u06d4 <code>ConsumerState<\/code> \u0622\u0632\u0627\u062f\u0627\u0646\u06c1 \u0637\u0648\u0631 \u067e\u0631 \u0679\u06cc\u067e \u0633\u06d2 \u0628\u0631\u0627\u06c1 \u0631\u0627\u0633\u062a \u0627\u06cc\u06a9 \u062c\u06cc\u0633\u06d2 \u0631\u06cc\u06a9\u0627\u0631\u0688\u0646\u06af \u0648\u0642\u0641\u06d2 \u0641\u0631\u0627\u06c1\u0645 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<pre><code class=\"language-python\">for k in range(lo, hi):\n    fresh.apply(tape[k].to_wire())\n<\/code><\/pre>\n<p>\u0631\u06cc \u067e\u0644\u06d2 \u062a\u0639\u0645\u06cc\u0631\u0627\u062a \u0627\u0648\u0631 \u0622\u0632\u0627\u062f\u0627\u0646\u06c1 \u0637\u0648\u0631 \u067e\u0631 \u062f\u0648\u0628\u0627\u0631\u06c1 \u062a\u0639\u0645\u06cc\u0631 \u0634\u062f\u06c1 \u0631\u06cc\u0627\u0633\u062a\u0648\u06ba \u06a9\u0648 \u062f\u0631\u062c \u0630\u06cc\u0644 \u0633\u06d2 \u0645\u062a\u0641\u0642 \u06c1\u0648\u0646\u0627 \u0686\u0627\u06c1\u06cc\u06d2:<\/p>\n<pre><code class=\"language-plaintext\">event count\ncumulative volume\n30-second VWAP\n2-minute VWAP\n<\/code><\/pre>\n<p>VWAP \u0642\u062f\u0631 \u06a9\u0627 \u0645\u0648\u0627\u0632\u0646\u06c1 \u0646\u0633\u0628\u062a\u0627 \u0631\u0648\u0627\u062f\u0627\u0631\u06cc \u0633\u06d2 \u06a9\u06cc\u0627 \u062c\u0627\u062a\u0627 \u06c1\u06d2\u06d4 <code>1e-12<\/code>. \u0679\u06cc\u0633\u0679 \u0627\u0633 \u0628\u0627\u062a \u06a9\u0648 \u0628\u06be\u06cc \u06cc\u0642\u06cc\u0646\u06cc \u0628\u0646\u0627\u062a\u0627 \u06c1\u06d2 \u06a9\u06c1 \u0639\u0627\u0645 \u067e\u0644\u06d2 \u0628\u06cc\u06a9 \u0644\u06cc\u0646 \u062f\u06cc\u0646 \u062f\u0631\u0645\u06cc\u0627\u0646 \u0645\u06cc\u06ba \u0646\u062f\u06cc \u0645\u06cc\u06ba \u0646\u06c1 \u067e\u06be\u0633\u0644 \u062c\u0627\u0626\u06d2\u06d4 <code>replay_reset<\/code> \u0627\u0648\u0631 <code>warmup_complete<\/code>.<\/p>\n<h3 id=\"heading-configure-pytest\">pytest \u062a\u0631\u062a\u06cc\u0628<\/h3>\n<p>\u063a\u06cc\u0631 \u0645\u0637\u0627\u0628\u0642\u062a \u067e\u0630\u06cc\u0631 \u0679\u06cc\u0633\u0679\u0648\u06ba \u0645\u06cc\u06ba <code>pytest-asyncio<\/code>. \u0628\u0646\u0627\u0646\u0627 <code>tests\/conftest.py<\/code>:<\/p>\n<pre><code class=\"language-python\">import pytest\n\ndef pytest_configure(config):\n    config.addinivalue_line(\n        \"markers\",\n        \"asyncio\"\n    )\n<\/code><\/pre>\n<p>\u067e\u06be\u0631 \u0634\u0627\u0645\u0644 \u06a9\u0631\u06cc\u06ba\u06d4 <code>pytest.ini<\/code> \u0645\u0646\u0635\u0648\u0628\u06d2 \u06a9\u06cc \u062c\u0691 \u0645\u06cc\u06ba:<\/p>\n<pre><code class=\"language-plaintext\">[pytest]\nasyncio_mode = auto\n<\/code><\/pre>\n<p>\u0645\u06a9\u0645\u0644 \u0633\u0648\u06cc\u0679 \u0686\u0644\u0627\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<pre><code class=\"language-shell\">pytest tests\/ -v\n<\/code><\/pre>\n<p>\u0631\u06cc\u06a9\u0627\u0631\u0688 \u0634\u062f\u06c1 \u0639\u0645\u0644\u062f\u0631\u0622\u0645\u062f \u06a9\u06d2 \u0646\u062a\u0627\u0626\u062c \u062f\u0631\u062c \u0630\u06cc\u0644 \u06c1\u06cc\u06ba:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/umang.pk\/wp-content\/uploads\/2026\/08\/1787822511_288_\u0645\u0627\u0631\u06a9\u06cc\u0679-\u0679\u0627\u0626\u0645-\u0645\u0634\u06cc\u0646-\u0628\u0646\u0627\u0646\u0627-\u0627\u0632\u06af\u0631-\u0627\u0648\u0631-\u0648\u06cc\u0628-\u0633\u0627\u06a9\u0679-\u06a9\u0627-\u0627\u0633\u062a\u0639\u0645\u0627\u0644.png\" alt=\"\u062a\u0635\u062f\u06cc\u0642 \u0686\u0644\u0627\u0626\u06cc\u06ba\u06d4\" style=\"display:block;margin:0 auto\" width=\"600\" height=\"400\" loading=\"lazy\" title=\"\"><\/p>\n<p>\u0679\u06cc\u0633\u0679 \u0627\u0633 \u0633\u06d2 \u0632\u06cc\u0627\u062f\u06c1 \u06a9\u0627 \u0627\u062d\u0627\u0637\u06c1 \u06a9\u0631\u062a\u0627 \u06c1\u06d2 \u06a9\u06c1 \u0622\u06cc\u0627 \u067e\u0644\u06d2 \u0628\u06cc\u06a9 \u0622\u062e\u0631 \u0645\u06cc\u06ba \u0679\u06cc\u067e \u06a9\u06d2 \u0622\u062e\u0631 \u062a\u06a9 \u067e\u06c1\u0646\u0686 \u062c\u0627\u062a\u0627 \u06c1\u06d2\u06d4 \u0627\u0633 \u0628\u0627\u062a \u06a9\u0648 \u06cc\u0642\u06cc\u0646\u06cc \u0628\u0646\u0627\u0626\u06cc\u06ba \u06a9\u06c1 \u067e\u0644\u06d2 \u0628\u06cc\u06a9 \u06a9\u06d2 \u0628\u0639\u062f \u0631\u06cc\u06a9\u0627\u0631\u0688\u0646\u06af \u06a9\u06cc \u062a\u0631\u062a\u06cc\u0628 \u0628\u0631\u0642\u0631\u0627\u0631 \u0631\u06c1\u06d2\u060c \u062a\u06cc\u0632 \u0631\u0641\u062a\u0627\u0631\u06cc \u06a9\u0627 \u0648\u0642\u062a \u0645\u062a\u0648\u0642\u0639 \u0631\u0648\u0627\u062f\u0627\u0631\u06cc \u06a9\u06d2 \u0627\u0646\u062f\u0631 \u0631\u06c1\u06d2\u060c \u062c\u0648 \u06a9\u0646\u0679\u0631\u0648\u0644 \u06a9\u0631\u062a\u0627 \u06c1\u06d2 \u0648\u0627\u0642\u0639\u0627\u062a \u06a9\u06cc \u062a\u0631\u062a\u06cc\u0628 \u06a9\u0648 \u0628\u0631\u0642\u0631\u0627\u0631 \u0631\u06a9\u06be\u062a\u0627 \u06c1\u06d2\u060c \u0627\u0648\u0631 \u06cc\u06c1 \u06a9\u06c1 \u0646\u06cc\u0648\u06cc\u06af\u06cc\u0634\u0646 \u06a9\u06d2 \u0628\u0639\u062f \u06a9\u06cc \u062a\u0639\u0645\u06cc\u0631 \u0646\u0648 \u06a9\u06cc \u062d\u0627\u0644\u062a \u0628\u0646\u06cc\u0627\u062f\u06cc \u0631\u06cc\u06a9\u0627\u0631\u0688 \u0634\u062f\u06c1 \u0688\u06cc\u0679\u0627 \u0633\u06d2 \u0627\u06cc\u06a9 \u0622\u0632\u0627\u062f \u062a\u0639\u0645\u06cc\u0631 \u0646\u0648 \u0633\u06d2 \u0645\u06cc\u0644 \u06a9\u06be\u0627\u062a\u06cc \u06c1\u06d2\u06d4<\/p>\n<h2 id=\"heading-conclusion\">\u0646\u062a\u06cc\u062c\u06c1<\/h2>\n<p>\u0645\u062c\u06be\u06d2 \u0627\u0633 \u062a\u0639\u0645\u06cc\u0631 \u06a9\u06d2 \u0628\u0627\u0631\u06d2 \u0645\u06cc\u06ba \u062c\u0648 \u0686\u06cc\u0632 \u0633\u0628 \u0633\u06d2 \u0632\u06cc\u0627\u062f\u06c1 \u067e\u0633\u0646\u062f \u0622\u0626\u06cc \u0648\u06c1 \u06cc\u06c1 \u06c1\u06d2 \u06a9\u06c1 \u062c\u0628 \u062f\u0648\u0628\u0627\u0631\u06c1 \u06af\u06be\u0691\u06cc \u062f\u06cc \u062c\u0627\u0626\u06d2 \u062a\u0648 \u0648\u06c1\u06cc \u062a\u0627\u0631\u06cc\u062e\u06cc \u0688\u06cc\u0679\u0627 \u0633\u06cc\u0679 \u06a9\u062a\u0646\u0627 \u0645\u062e\u062a\u0644\u0641 \u0645\u062d\u0633\u0648\u0633 \u06c1\u0648\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<p>\u06c1\u0645 \u0646\u06d2 EODHD \u0645\u06cc\u06ba \u0627\u06cc\u06a9 \u0645\u06a9\u0645\u0644 AAPL \u0633\u06cc\u0634\u0646 \u06a9\u06d2 \u0633\u0627\u062a\u06be \u0622\u063a\u0627\u0632 \u06a9\u06cc\u0627 \u0627\u0648\u0631 \u0627\u0633 \u06a9\u06d2 \u0633\u0627\u062a\u06be \u0627\u062e\u062a\u062a\u0627\u0645 \u067e\u0630\u06cc\u0631 \u06c1\u0648\u0627 \u062c\u0633 \u0646\u06d2 \u06c1\u0645\u06cc\u06ba \u0622\u06c1\u0633\u062a\u06c1 \u0622\u06c1\u0633\u062a\u06c1 \u0622\u06af\u06d2 \u0628\u0691\u06be\u0646\u06d2\u060c \u0622\u06af\u06d2 \u0628\u0691\u06be\u0646\u06d2\u060c \u062f\u0631\u0645\u06cc\u0627\u0646 \u0645\u06cc\u06ba \u062a\u0648\u0642\u0641 \u06a9\u0631\u0646\u06d2\u060c \u062f\u0646 \u0645\u06cc\u06ba \u0645\u062e\u062a\u0644\u0641 \u067e\u0648\u0627\u0626\u0646\u0679\u0633 \u067e\u0631 \u0686\u06be\u0644\u0627\u0646\u06af \u0644\u06af\u0627\u0646\u06d2\u060c \u0627\u0648\u0631 \u062c\u0627\u0631\u06cc \u0631\u06a9\u06be\u0646\u06d2 \u06a9\u06cc \u0627\u062c\u0627\u0632\u062a \u062f\u06cc \u062c\u0628 \u06a9\u06c1 \u0635\u0627\u0631\u0641 \u0635\u0631\u0641 \u0627\u0633 \u067e\u0631 \u0631\u062f\u0639\u0645\u0644 \u0638\u0627\u06c1\u0631 \u06a9\u0631\u062a\u0627 \u06c1\u06d2 \u062c\u0648 \u0627\u0646\u06c1\u06cc\u06ba \u0627\u0628 \u062a\u06a9 \u062d\u0627\u0635\u0644 \u06c1\u0648\u0627 \u06c1\u06d2\u06d4<\/p>\n<p>\u0627\u0633 \u0645\u0646\u0635\u0648\u0628\u06d2 \u06a9\u0648 \u0645\u0632\u06cc\u062f \u062a\u0631\u0642\u06cc \u062f\u06cc\u0646\u06d2 \u06a9\u06d2 \u0644\u06cc\u06d2 \u0627\u0628\u06be\u06cc \u0628\u06be\u06cc \u06a9\u0627\u0641\u06cc \u06af\u0646\u062c\u0627\u0626\u0634 \u06c1\u06d2\u06d4 \u0631\u06cc \u067e\u0644\u06d2 \u0645\u062a\u0639\u062f\u062f \u0639\u0644\u0627\u0645\u062a\u0648\u06ba\u060c \u0628\u06be\u0631\u067e\u0648\u0631 \u0645\u0627\u0631\u06a9\u06cc\u0679 \u0627\u0633\u0679\u06cc\u0679\u0633\u060c \u0645\u062a\u0639\u062f\u062f \u0646\u06cc\u0686\u06d2 \u062f\u06be\u0627\u0631\u06d2 \u0635\u0627\u0631\u0641\u06cc\u0646\u060c \u062c\u0627\u0631\u06cc \u0631\u06cc \u067e\u0644\u06d2 \u0633\u06cc\u0634\u0646\u0632\u060c \u0627\u0648\u0631 \u06cc\u06c1\u0627\u06ba \u062a\u06a9 \u06a9\u06c1 \u062d\u06a9\u0645\u062a \u0639\u0645\u0644\u06cc \u0627\u0648\u0631 \u0639\u0645\u0644 \u062f\u0631\u0622\u0645\u062f \u06a9\u06d2 \u0627\u062c\u0632\u0627\u0621 \u06a9\u0648 \u0628\u0631\u0627\u06c1 \u0631\u0627\u0633\u062a \u062f\u06be\u0627\u0631\u06d2 \u0633\u06d2 \u0645\u0646\u0633\u0644\u06a9 \u06a9\u0631\u0646\u06d2 \u06a9\u06cc \u062d\u0645\u0627\u06cc\u062a \u06a9\u0631 \u0633\u06a9\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4 \u06c1\u0645 \u062c\u0627\u0646 \u0628\u0648\u062c\u06be \u06a9\u0631 \u0627\u0646 \u062d\u0635\u0648\u06ba \u06a9\u0648 \u0645\u0648\u062c\u0648\u062f\u06c1 \u0648\u0631\u0698\u0646 \u0645\u06cc\u06ba \u0631\u06a9\u06be\u062a\u06d2 \u06c1\u06cc\u06ba\u060c \u0644\u06cc\u06a9\u0646 \u0627\u0628 \u06c1\u0645 \u0628\u0646\u06cc\u0627\u062f\u06cc \u067e\u0644\u06d2 \u0628\u06cc\u06a9 \u067e\u0631\u062a \u067e\u0631 \u062a\u0639\u0645\u06cc\u0631 \u06a9\u0631 \u0633\u06a9\u062a\u06d2 \u06c1\u06cc\u06ba\u06d4<\/p>\n<p>\u0645\u06cc\u0631\u06d2 \u0646\u0632\u062f\u06cc\u06a9 \u06cc\u06c1 \u0627\u0633 \u0645\u0646\u0635\u0648\u0628\u06d2 \u06a9\u0627 \u0627\u06cc\u06a9 \u0645\u0641\u06cc\u062f \u0646\u062a\u06cc\u062c\u06c1 \u06c1\u06d2\u06d4 EODHD \u062a\u0627\u0631\u06cc\u062e\u06cc \u0648\u0627\u0642\u0639\u0627\u062a \u0641\u0631\u0627\u06c1\u0645 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u060c \u0644\u06cc\u06a9\u0646 \u0631\u06cc \u067e\u0644\u06d2 \u0644\u06cc\u0626\u0631 \u062f\u0648\u0633\u0631\u06d2 \u0633\u0627\u0641\u0679 \u0648\u06cc\u0626\u0631 \u06a9\u0648 \u0627\u0646 \u0648\u0627\u0642\u0639\u0627\u062a \u06a9\u0648 \u0688\u06cc\u0679\u0627 \u0633\u06cc\u0679 \u06a9\u06d2 \u0628\u062c\u0627\u0626\u06d2 \u062a\u062c\u0627\u0631\u062a\u06cc \u062f\u0646 \u06a9\u06d2 \u0637\u0648\u0631 \u067e\u0631 \u062a\u062c\u0631\u0628\u06c1 \u06a9\u0631\u0646\u06d2 \u06a9\u06cc \u0627\u062c\u0627\u0632\u062a \u062f\u06cc\u062a\u0627 \u06c1\u06d2 \u062c\u06c1\u0627\u06ba \u06c1\u0645 \u067e\u06c1\u0644\u06d2 \u06c1\u06cc \u062c\u0627\u0646\u062a\u06d2 \u06c1\u06cc\u06ba \u06a9\u06c1 \u062f\u0646 \u06a9\u06cc\u0633\u06d2 \u062e\u062a\u0645 \u06c1\u0648\u062a\u0627 \u06c1\u06d2\u06d4<\/p>\n<\/p><\/div>\n","protected":false},"excerpt":{"rendered":"<p>\u062a\u0627\u0631\u06cc\u062e\u06cc \u0645\u0627\u0631\u06a9\u06cc\u0679 \u06a9\u0627 \u0688\u06cc\u0679\u0627 \u0639\u0627\u0645 \u0637\u0648\u0631 \u067e\u0631 \u0627\u06cc\u06a9 \u0645\u06a9\u0645\u0644 \u0688\u06cc\u0679\u0627\u0633\u06cc\u0679 \u06a9\u06d2 \u0637\u0648\u0631 \u067e\u0631 \u0622\u062a\u0627 \u06c1\u06d2\u06d4 \u06cc\u06c1 \u062a\u062c\u0632\u06cc\u06c1 \u06a9\u06d2 \u0644\u06cc\u06d2 \u0622\u0633\u0627\u0646 \u06c1\u06d2\u060c \u0644\u06cc\u06a9\u0646 \u06cc\u06c1 \u0627\u0633 \u0633\u06d2 \u0628\u06c1\u062a \u0645\u062e\u062a\u0644\u0641 \u06c1\u06d2 \u06a9\u06c1 \u06a9\u0633 \u0637\u0631\u062d \u0679\u0631\u06cc\u0688\u0646\u06af \u0633\u0627\u0641\u0679 \u0648\u06cc\u0626\u0631 \u062d\u0642\u06cc\u0642\u06cc \u0645\u0627\u0631\u06a9\u06cc\u0679\u0648\u06ba \u06a9\u0627 \u062a\u062c\u0631\u0628\u06c1 \u06a9\u0631\u062a\u0627 \u06c1\u06d2\u06d4 \u067e\u06cc\u062f\u0627\u0648\u0627\u0631 \u0645\u06cc\u06ba\u060c \u0648\u0627\u0642\u0639\u0627\u062a \u0627\u06cc\u06a9 \u0648\u0642\u062a \u0645\u06cc\u06ba \u06c1\u0648\u062a\u06d2 \u06c1\u06cc\u06ba\u060c \u0645\u0633\u062a\u0642\u0628\u0644 \u0646\u0627\u0645\u0639\u0644\u0648\u0645 \u06c1\u06d2\u060c \u0627\u0648\u0631 \u062a\u0645\u0627\u0645 \u0641\u06cc\u0635\u0644\u06d2 \u0635\u0631\u0641 [&hellip;]<\/p>\n","protected":false},"author":7,"featured_media":28372,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"site-sidebar-layout":"default","site-content-layout":"","ast-site-content-layout":"default","site-content-style":"default","site-sidebar-style":"default","ast-global-header-display":"","ast-banner-title-visibility":"","ast-main-header-display":"","ast-hfb-above-header-display":"","ast-hfb-below-header-display":"","ast-hfb-mobile-header-display":"","site-post-title":"","ast-breadcrumbs-content":"","ast-featured-img":"","footer-sml-layout":"","ast-disable-related-posts":"","theme-transparent-header-meta":"","adv-header-id-meta":"","stick-header-meta":"","header-above-stick-meta":"","header-main-stick-meta":"","header-below-stick-meta":"","astra-migrate-meta-layouts":"default","ast-page-background-enabled":"default","ast-page-background-meta":{"desktop":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"ast-content-background-meta":{"desktop":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"footnotes":""},"categories":[1],"tags":[],"class_list":["post-28371","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-blog"],"_links":{"self":[{"href":"https:\/\/umang.pk\/ur\/wp-json\/wp\/v2\/posts\/28371","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/umang.pk\/ur\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/umang.pk\/ur\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/umang.pk\/ur\/wp-json\/wp\/v2\/users\/7"}],"replies":[{"embeddable":true,"href":"https:\/\/umang.pk\/ur\/wp-json\/wp\/v2\/comments?post=28371"}],"version-history":[{"count":1,"href":"https:\/\/umang.pk\/ur\/wp-json\/wp\/v2\/posts\/28371\/revisions"}],"predecessor-version":[{"id":28373,"href":"https:\/\/umang.pk\/ur\/wp-json\/wp\/v2\/posts\/28371\/revisions\/28373"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/umang.pk\/ur\/wp-json\/wp\/v2\/media\/28372"}],"wp:attachment":[{"href":"https:\/\/umang.pk\/ur\/wp-json\/wp\/v2\/media?parent=28371"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/umang.pk\/ur\/wp-json\/wp\/v2\/categories?post=28371"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/umang.pk\/ur\/wp-json\/wp\/v2\/tags?post=28371"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}