۱۔ آغاز: ٹرمپ کے ہاتھوں کا K-لائن چارٹ
خبروں کی بروقتیت سے انکار ممکن نہیں۔ امریکی حملے کی خبر ایران پر آنے کے بعد، خام تیل کی قیمتوں میں مختصر وقت میں زبردست اضافہ ہوا، اور اس عمل میں ٹرمپ اور ایران کے بیانات جیسے عوامل مسلسل ایک دوسرے کو تقویت دیتے رہے، جس نے قیمتوں کو نئی نئی حدود میں دھکیل دیا۔
ہم اکثر مذاق میں کہتے ہیں کہ "ٹرمپ ہاتھوں سے K-لائن بناتا ہے" — اکثر اوقات قیمتوں میں شدید اتار چڑھاؤ تکنیکی اشاریوں سے نہیں بلکہ ایک ٹوئیٹ، ایک تقریر، یا ایک پالیسی بیان سے براہ راست پیدا ہوتا ہے۔ تکنیکی تجزیہ آپ کو بتاتا ہے کہ "اب کہاں ہیں"، لیکن خبریں ہی وہ کلیدی متغیر ہوتی ہیں جو بتاتی ہیں "یہاں کیوں ہیں اور آگے کہاں جا سکتے ہیں"۔

خبروں کی اہمیت سے انکار ممکن نہیں، لیکن مسئلہ بھی حقیقت پسندانہ ہے: کوئی بھی شخص 24 گھنٹے چارٹ اور خبروں پر نظر نہیں رکھ سکتا، اور معلومات کے سیلاب میں پہلی مرتبہ اس خبر کو پکڑنا اور بھی مشکل ہے جو واقعی مارکیٹ کو متحرک کر سکے۔ چنانچہ ایک سادہ سا خیال ابھرا — کیا خبروں کو براہ راست K-لائن چارٹ پر "پینٹ" کیا جا سکتا ہے، تاکہ قیمت اور خبریں ایک ہی ویو میں دکھائی دیں؟ کم از کم "دیکھنے" کا مسئلہ تو حل ہو جائے۔
۲۔ خبروں کے ذرائع کا انتخاب: MCP کے ذریعے Jin10 تک رسائی
خبروں کو جوڑنے کے لیے پہلا قدم ایک ایسا ذریعہ تلاش کرنا ہے جو تیزی سے اپ ڈیٹ ہو اور نسبتاً معیاری ڈھانچہ رکھتا ہو۔ اس بار ہم نے Jin10 ڈیٹا کو منتخب کیا، اور MCP (Model Context Protocol) کے ذریعے رسائی حاصل کی، list_flash (فوری خبریں) اور list_news (اطلاعات) دونوں قسم کے انٹرفیس کو کال کرتے ہوئے۔
یہاں ہم Jin10 کے بارے میں زیادہ تفصیل میں نہیں جانا چاہتے — یہ صرف ایک انتخاب ہے جو ہم فی الحال استعمال کر رہے ہیں؛ خیال اور مخصوص خبروں کے ذریعے کو الگ رکھا گیا ہے، جب تک کوئی ذریعہ وقت کے ساتھ عنوان/متن فراہم کرتا ہے اور MCP کے معیاری طریقے سے کال کیا جا سکتا ہے، اسے تبدیل کیا جا سکتا ہے۔ اہم بات اس پرت کا ڈیزائن ہے، نہ کہ کسی مخصوص ٹول سے چپک جانا۔
MCP کا کنکشن اور سیشن مینجمنٹ اس نظام کا کافی "نچلی سطح" لیکن اہم حصہ ہے:
python
def _mcp_post(payload, is_notification=False):
global _mcp_session_id, _mcp_req_id
if not is_notification:
_mcp_req_id += 1
payload["id"] = _mcp_req_id
body = json.dumps(payload, ensure_ascii=False).encode()
req = urllib.request.Request(
JIN10_MCP_URL, data=body, headers=_mcp_headers(), method="POST"
)
try:
with urllib.request.urlopen(req, timeout=30) as resp:
sid = resp.headers.get("Mcp-Session-Id")
if sid:
_mcp_session_id = sid
if resp.status == 202:
return {}
text = resp.read().decode("utf-8", errors="replace")
except urllib.error.HTTPError as e:
raise RuntimeError("HTTP %d: %s" % (e.code, e.read().decode()[:400]))
except urllib.error.URLError as e:
raise RuntimeError("Network: " + str(e))
return _mcp_parse(text)
def mcp_init():
global _mcp_ready
mcp_rpc("initialize", {
"protocolVersion": "2025-11-25",
"capabilities": {},
"clientInfo": {"name": "fuse-fmz", "version": "1.0"},
})
mcp_notify("notifications/initialized")
_mcp_ready = True
Log("MCP ready session_id=" + (_mcp_session_id or "(none)"))
سیشن قائم ہونے کے بعد، خبریں کھینچنا دو ٹول کالز پر مشتمل ہوتا ہے، پھر ایک متحد شکل میں معمول بندی اور ڈپلیکیشن کو ہٹایا جاتا ہے:
python
def refresh_news():
global _cached_news, _last_news_at, _mcp_ready
if not JIN10_MCP_TOKEN:
return
now = int(time.time())
if now - _last_news_at < NEWS_REFRESH_SEC and _cached_news:
return
_last_news_at = now
try:
if not _mcp_ready:
mcp_init()
flash_raw = mcp_call_tool("list_flash")
news_raw = mcp_call_tool("list_news")
combined = (
_normalize(_extract_items(flash_raw), "flash") +
_normalize(_extract_items(news_raw), "news")
)
combined.sort(key=lambda x: x["ts"], reverse=True)
_cached_news = combined[:80]
Log("News updated: %d items" % len(_cached_news))
except Exception as e:
Log("News refresh failed: " + str(e))
_mcp_ready = False
مختلف خبروں کے ذرائع سے واپس ملنے والے فیلڈ نام بہت مختلف ہوتے ہیں (title/content/introduction، time/ts/created_at...)، اس لیے درمیان میں ایک پرت _extract_items + _normalize شامل کی گئی ہے، جو تمام فارمیٹس کو معیاری ساخت {ts, time, title, source, full_text} میں تبدیل کرتی ہے، تاکہ بعد میں چارٹ اور فلٹرنگ منطق کو یہ جاننے کی ضرورت نہ ہو کہ ڈیٹا کس انٹرفیس سے آیا ہے۔
نوٹ: استعمال کے لیے MCP API کی درخواست ضروری ہے۔
۳۔ بنیادی خصوصیت: خبروں کو K-لائن پر "لگا" دینا
اب اس ٹول کا واقعی دلچسپ حصہ آتا ہے — خبروں اور K-لائن کو ایک ہی چارٹ میں رکھنا۔
ہم نے چارٹ میں ایک دوسری سیریز شامل کی، جس کی قسم flags ہے، اور اسے K-لائن سیریز پر لگا دیا، بطور "خبروں کے نشانات پرت":
python
def init_chart(symbol):
global _chart
_chart = Chart({
"__isStock": True,
"chart": {"style": {"fontFamily": "Microsoft YaHei, SimHei, Arial, sans-serif"}},
"title": {"text": "FUSE " + symbol},
"xAxis": {"type": "datetime"},
"series": [
{
"id": "kline",
"type": "candlestick",
"name": symbol,
"data": [],
},
{
"type": "flags",
"name": "News",
"onSeries": "kline",
"shape": "circlepin",
"color": "#F59E0B",
"fillColor": "#F59E0B",
"width": 16,
"data": [],
},
],
})
_chart.reset()
ہر بار ریفریش کرتے وقت، پہلے K-line ڈیٹا کو اضافی طور پر اپ ڈیٹ کریں، پھر کلیدی الفاظ کی بنیاد پر "اہم" خبروں کو فلٹر کریں اور انہیں وقت کے مطابق متعلقہ K-line بار پر لگائیں:
python
def draw_chart(records):
global _last_bar_time, _last_news_hash, _flagged_news_ts
if not _chart or not records:
return
# خبروں میں تبدیلی کی جانچ کریں، اگر تبدیلی ہو تو چارٹ ری سیٹ کر کے دوبارہ ڈرا کریں
news_hash = hash(tuple(n.get("ts", 0) for n in _cached_news[:10]))
news_changed = (news_hash != _last_news_hash)
if news_changed:
_chart.reset()
_last_bar_time = 0
_last_news_hash = news_hash
_flagged_news_ts = set()
# series 0: K-line، اضافی طور پر add
for r in records:
t = r['Time']
bar = [t, r['Open'], r['High'], r['Low'], r['Close']]
if t > _last_bar_time:
_chart.add(0, bar)
_last_bar_time = t
elif t == _last_bar_time:
_chart.add(0, bar, -1)
# series 1: کلیدی الفاظ والی خبروں کے flag، K-line بار کے وقت کے مطابق
if not _cached_news:
return
kws = [k.strip() for k in NEWS_KEYWORD.split("|") if k.strip()]
kw_news = [n for n in _cached_news if not kws or any(k in n.get("full_text", n["title"]) for k in kws)]
if not kw_news:
return
p_ms = PERIOD_MS.get(KLINE_PERIOD, 60000)
first = records[0]['Time']
last = records[-1]['Time']
by_bar = {}
for n in kw_news:
if not n.get("ts"):
continue
key = (n["ts"] // p_ms) * p_ms
if key not in by_bar:
by_bar[key] = n
for ts, item in sorted(by_bar.items()):
if not (first <= ts <= last):
continue
if ts in _flagged_news_ts:
continue
_chart.add(1, {
"x": ts,
"title": "📰",
"text": item["title"][:100],
})
_flagged_news_ts.add(ts)
نتیجہ یہ ہے کہ: چارٹ پر جب بھی 📰 کا نشان نظر آئے، ماؤس اس پر لے جانے پر اس خبر کا عنوان نظر آئے گا، اور اس کی پوزیشن اسی خبر کے وقوع پذیر ہونے والے وقت کے مطابق K-line پر ہوگی۔ قیمت کے موڑ اور خبر کے وقت کو پہلی بار ایک ہی فریم میں ایک بدیہی انداز میں دکھایا گیا ہے — اب آپ کو "یہ حصہ کیوں ہے" دیکھنے کے لیے دو ونڈوز کے درمیان سوئچ کرنے کی ضرورت نہیں۔
NEWS_KEYWORD میں | کے ذریعے متعدد کلیدی الفاظ شامل کیے جا سکتے ہیں (مثلاً "ایران|شرح سود میں اضافہ|نان فارم|ٹیرف")، سسٹم ان خبروں کو ترجیح دے گا جو کلیدی الفاظ سے مماثل ہوں، تاکہ چارٹ غیر متعلقہ فوری خبروں سے بھر نہ جائے۔
چار: اسٹیٹس پینل: مارکیٹ، پوزیشن، خبریں ایک سکرین پر
چارٹ کے علاوہ، ہم نے اسٹیٹس ٹیبلز کا ایک سیٹ بھی بنایا ہے جو LogStatus کے ذریعے آؤٹ پٹ ہوتا ہے، جس میں ریئل ٹائم مارکیٹ ڈیٹا، اکاؤنٹ ایکویٹی اور منافع/نقصان، موجودہ پوزیشنز، کلیدی الفاظ سے مماثل خبریں، اور تازہ ترین تمام فوری خبریں شامل ہیں:
python
def make_status(symbol, ticker, positions, equity):
# 4. کلیدی الفاظ والی خبریں (ماخذ کے بجائے مماثل کلیدی الفاظ دکھائیں)
kws = [k.strip() for k in NEWS_KEYWORD.split("|") if k.strip()]
kw_rows = []
for item in _cached_news[:40]:
t = item.get("time") or (_D(item["ts"]) if item.get("ts") else "-")
title = item["title"][:90]
text = item.get("full_text", item["title"])
hit_kws = [k for k in kws if k in text]
if hit_kws:
kw_rows.append([t, "/".join(hit_kws), title])
if not kw_rows:
kw_rows = [["-", "-", "کلیدی الفاظ سے متعلق کوئی خبر نہیں"]]
اس کے ساتھ ایک سادہ دستی کمانڈ انٹرفیس بھی شامل ہے — لمبا کھولیں، چھوٹا کھولیں، لمبا بند کریں، چھوٹا بند کریں، ایک کلک سے سب بند کریں، آرڈر کی مقدار تبدیل کریں، یہ سب GetCommand() کے ذریعے موصول ہوتے ہیں:
python
def handle_command(symbol):
global _cur_amount, _last_news_at
cmd = GetCommand()
if not cmd:
return
Log("CMD: " + cmd)
parts = cmd.split(":")
key = parts[0]
val = parts[1] if len(parts) > 1 else ""
if key == "openLong": market_order(symbol, "openLong", _cur_amount)
elif key == "openShort": market_order(symbol, "openShort", _cur_amount)
elif key == "closeLong": market_order(symbol, "closeLong", _cur_amount)
elif key == "closeShort": market_order(symbol, "closeShort", _cur_amount)
elif key == "closeAll": close_all(symbol)
elif key == "amount":
_cur_amount = float(val)
Log("Amount updated: " + str(_cur_amount))
مکمل طور پر، FUSE بنیادی طور پر ایک "معلومات کا انضمام + دستی عمل" پر مبنی دیکھنے کا پینل ہے: یہ قیمت، خبریں، پوزیشنز اور اکاؤنٹ کی صورتحال کو ایک ہی اسکرین پر رکھنے کی کوشش کرتا ہے، فیصلہ سازی اب بھی مکمل طور پر انسان پر منحصر ہے — یہ آپ کے لیے فیصلہ نہیں کرتا، لیکن یہ یقینی بنانے کی کوشش کرتا ہے کہ آپ فیصلہ کرتے وقت کم سے کم کچھ نظر انداز کریں۔
پانچویں: حدیں — انسان، اب بھی سب سے بڑا متغیر
اس ورژن کی حدیں کافی واضح ہیں، اور ہم ان سے نظریں چرانے کا نہیں سوچتے۔
پہلی، خبروں اور قیمتوں کے درمیان تعلق "موٹے درجے" کا ہے — صرف خبروں کو ٹائم اسٹیمپ کے مطابق متعلقہ K-line بار پر لٹکا دیا گیا ہے، مواد کی سطح پر کوئی تشریح نہیں کی گئی۔ ایک خبر مثبت ہے یا منفی، اور یہ مارکیٹ میں حرکت لائے گی یا نہیں، اس کا فیصلہ مکمل طور پر انسان کرتا ہے۔
دوسری، کلیدی الفاظ کا فلٹر اپنے آپ میں ایک سادہ طریقہ ہے۔ کلیدی الفاظ کا ملنا اس بات کی ضمانت نہیں دیتا کہ خبر واقعی اہم ہے، اور نہ ملنے کا مطلب یہ نہیں کہ خبر غیر اہم ہے۔ اس درمیان، فرد کی سوچ، تجربہ، اور یہاں تک کہ اس دن کی کیفیت بھی بہت زیادہ وزن رکھ سکتی ہے — ایک ہی خبر کو مختلف لوگ ایک ہی چارٹ پر دیکھ کر بالکل مختلف نتائج اخذ کر سکتے ہیں۔
تیسری، پورا عمل اب بھی "انسان لوپ میں" ہے، ردعمل کی رفتار انسان کی ردعمل کی رفتار تک محدود ہے، جبکہ اکثر اوقات خبروں پر مارکیٹ کا ردعمل منٹوں یا سیکنڈوں میں آتا ہے۔
اگر آپ اس سمت میں دلچسپی رکھتے ہیں، تو ہم بعد میں بڑے ماڈل پر مبنی ایک خودکار ورژن بنانے کی کوشش کریں گے، جہاں ماڈل خبروں کی ابتدائی تشریح اور اہمیت کا فیصلہ کرے گا، تاکہ انسانی فیصلہ سازی میں مدد یا متبادل فراہم کر سکے۔ اگر دلچسپی ہو تو براہ کرم فالو کرتے رہیں۔
حکمت عملی کا سورس کوڈ: ریئل ٹائم نیوز فیوز سسٹم
- 1




