Market Maker কেন অর্থ হারান: Adverse Selection
Market maker কেন অর্থ হারান? Adverse selection প্রধান কারণ। Markout curve কীভাবে এটি মাপে, পাশাপাশি inventory risk ও queue position cost দেখুন।
Market makers adverse selection-এর কারণে অর্থ হারান: যে ট্রেডার কোনো offer তুলে নেন, তিনি প্রায়ই এমন একজন, যিনি ইতিমধ্যে জানেন যে offer-টি stale। প্রতিটি fill প্রায় অর্ধেক spread-এর সমান একটি ছোট credit দিয়ে শুরু হয়, আর পরের কয়েক সেকেন্ডে নির্ধারিত হয় সেই credit-এর কতটা টিকে থাকবে। এই পরিমাপের সরঞ্জাম হলো markout—কোনো fill-এর পর নির্দিষ্ট সময়সীমায় signed price change। নিচের panelগুলো trade ও quote prints থেকে প্রকৃত markout curve তৈরি করে। একই ledger-এর revenue side নিয়ে আমাদের সহগামী লেখায় market makers কীভাবে অর্থ উপার্জন করেন ব্যাখ্যা করা হয়েছে।
ট্রেডিংয়ে adverse selection কী?
একজন market maker একই সময়ে দুটি দাম প্রকাশ করেন: কেনার জন্য bid এবং বিক্রির জন্য offer। প্রতিটির সঙ্গে নির্দিষ্ট size থাকে। এই দুই দামের ব্যবধান হলো bid ask spread, আর ব্যবসাটির ভিত্তি হলো হিসাব। bid-এ কিনুন, offer-এ বিক্রি করুন, দিনে কয়েক দশ হাজার বার পুনরাবৃত্তি করুন—তাহলে প্রতিটি round trip-এ গড়ে spread-এর কাছাকাছি অর্থ সংগ্রহ হবে।
এই হিসাব ধরে নেয় যে দুই দিকের অর্ডার সমান ভারসাম্যে আসে। বাস্তবে তা হয় না। একটি resting quote হলো এমন একটি standing option, যা যে কেউ নিজের পছন্দের মুহূর্তে exercise করতে পারে। সবচেয়ে মনোযোগী ট্রেডাররা সেরা মুহূর্তগুলো বেছে নেন। কোনো fund বড় parent order কার্যকর করার সময় offer সস্তা থাকলে কিনতে থাকে। কোনো system correlated instrument-এ দাম নড়তে দেখার পর এমন দিক বেছে নেয়, যেটি এখনও repricing করেনি।
Adverse selection বলতে এই মিশ্রণের একতরফা ঝোঁককে বোঝায়: market maker যে fills পান, সেগুলো এমন ট্রেডারদের দিকে বেশি ঝুঁকে থাকে যারা ওই fills সবচেয়ে বেশি চেয়েছিলেন। এর লক্ষণ হলো market maker যে spread quote করেন এবং যে spread ধরে রাখতে পারেন, তাদের মধ্যে ব্যবধান।
Market making-এ markout কী?
প্রতিটি fill-এর পর markout একটি প্রশ্নের উত্তর দেয়: আমি যে side-এ ছিলাম, সেই দিক থেকে মাপলে নির্দিষ্ট কয়েক সেকেন্ড পরে দাম কোথায় ছিল? ধরুন, midpoint $50.00 থাকা অবস্থায় একজন market maker 100টি শেয়ার $50.02 দামে বিক্রি করলেন। ওই fill-এ প্রতি শেয়ারে 2 cents credit তৈরি হলো, desk-এর এককে 20 mils; 1 mil হলো এক cent-এর এক দশমাংশ। 60 সেকেন্ড পরে midpoint যদি $50.04-এ উঠে যায়, তাহলে 60 second markout হবে minus 20 mils। শুরুর credit হারিয়ে গেছে, সঙ্গে আরও সমপরিমাণ অর্থও গেছে।
কোনো সময়সীমার প্রতিটি fill-এর ওপর এই হিসাবের গড় নিয়ে horizon-এর বিপরীতে plot করলে markout curve পাওয়া যায়। নিচের panel-এ বৃহস্পতিবার, May 14, 2026-এর দুপুরের 3 ঘণ্টার সময়সীমায় AAPL-এর জন্য এমন একটি curve তৈরি করা হয়েছে। প্রতিটি print যে সেকেন্ডে হয়েছে, সেই সেকেন্ডের midpoint-এর সঙ্গে sign করা হয়েছে: midpoint-এর ওপরে হওয়া print taker buying হিসেবে গণ্য হয়েছে, ফলে market maker sell side-এ ছিলেন।
প্রতিটি সংখ্যার পেছনের সঠিক SQL
WITH
qs AS (
SELECT toUnixTimestamp(toDateTime(sip_timestamp)) AS ts,
avg((toFloat64(bid_price) + toFloat64(ask_price)) / 2) AS mid
FROM global_markets.cache_stocks_quotes
WHERE ticker = 'AAPL'
AND sip_timestamp >= '2026-05-14 14:00:00'
AND sip_timestamp < '2026-05-14 17:06:00'
AND bid_price > 0 AND ask_price > bid_price
GROUP BY ts
),
fills AS (
SELECT t.ts AS ts, t.px AS px, t.shares AS shares, q.mid AS mid_at_fill,
if(t.px > q.mid, 1, -1) AS taker_side
FROM (
SELECT toUnixTimestamp(toDateTime(sip_timestamp)) AS ts,
toFloat64(price) AS px, toUInt64(size) AS shares
FROM global_markets.stocks_trades
WHERE ticker = 'AAPL'
AND sip_timestamp >= '2026-05-14 14:00:00'
AND sip_timestamp < '2026-05-14 17:00:00'
AND size > 0
) AS t
INNER JOIN qs AS q ON q.ts = t.ts
WHERE t.px != q.mid AND abs(t.px / q.mid - 1) < 0.02
)
SELECT
concat('+', toString(e.secs), 's') AS horizon,
round(1000 * avg(e.taker_side * (e.px - e.mid_at_fill)), 2) AS edge_at_fill_mils,
round(1000 * avg(e.taker_side * (e.px - f.mid)), 2) AS edge_after_mils
FROM (
SELECT toUInt32(ts + secs) AS future_ts, secs, px, mid_at_fill, taker_side
FROM (SELECT *, arrayJoin([1, 5, 15, 30, 60, 300]) AS secs FROM fills)
) AS e
INNER JOIN qs AS f ON f.ts = e.future_ts
GROUP BY e.secs
ORDER BY e.secsপ্রথম series হলো fill-এর মুহূর্তের credit—print এবং midpoint-এর ব্যবধান—যার গড় 19.66 mils per share। দ্বিতীয় series দেখায় midpoint কিছুটা সময় নড়ার পর একই fills-এর মূল্য কত: 1 second পরে 20.5 mils এবং 5 minutes পরে 9.81 mils। যেকোনো horizon-এ দুই series-এর ব্যবধানই markout, যা market maker quote করা spread থেকে কমে যায়।
যে curve দ্রুত নেমে পরে সমতল হয়, তা বোঝায় market maker তাৎক্ষণিক repricing-এর খরচ বহন করছেন, কিন্তু credit-এর অবশিষ্ট অংশ ধরে রাখতে পারছেন। যে curve প্রতিটি horizon-এ একইভাবে ঢালু থাকে, তা বোঝায় fills এমন দামের ভুল দিকে পড়ছে, যে দাম ক্রমাগত এগিয়ে যাচ্ছে। প্রথম আকৃতি ব্যবসা পরিচালনার স্বাভাবিক খরচ। দ্বিতীয়টি এমন quote-এর লক্ষণ, যা পরিবর্তন করা দরকার।
কোন fills toxic flow?
এখানে toxic শব্দটি একটি কারিগরি অর্থে ব্যবহৃত হচ্ছে। কোনো বড় sample-এ প্রতিটি horizon-এ কোনো flow-এর markout curve market maker-এর বিপরীতে ঢালু হলে সেই flow toxic। Desk-গুলো যে লেবেল দেখতে পায়, সেগুলো দিয়ে fills ভাগ করে: print size, venue, order type, counterparty identifier। Public tape-এ বহন করা লেবেলটি হলো size।
প্রতিটি সংখ্যার পেছনের সঠিক SQL
WITH
qs AS (
SELECT toUnixTimestamp(toDateTime(sip_timestamp)) AS ts,
avg((toFloat64(bid_price) + toFloat64(ask_price)) / 2) AS mid
FROM global_markets.cache_stocks_quotes
WHERE ticker = 'AAPL'
AND sip_timestamp >= '2026-05-14 14:00:00'
AND sip_timestamp < '2026-05-14 17:06:00'
AND bid_price > 0 AND ask_price > bid_price
GROUP BY ts
),
fills AS (
SELECT t.ts AS ts, t.px AS px, t.shares AS shares, q.mid AS mid_at_fill,
if(t.px > q.mid, 1, -1) AS taker_side
FROM (
SELECT toUnixTimestamp(toDateTime(sip_timestamp)) AS ts,
toFloat64(price) AS px, toUInt64(size) AS shares
FROM global_markets.stocks_trades
WHERE ticker = 'AAPL'
AND sip_timestamp >= '2026-05-14 14:00:00'
AND sip_timestamp < '2026-05-14 17:00:00'
AND size > 0
) AS t
INNER JOIN qs AS q ON q.ts = t.ts
WHERE t.px != q.mid AND abs(t.px / q.mid - 1) < 0.02
)
SELECT
multiIf(s.shares < 100, 'under 100 shares',
s.shares < 500, '100 to 499',
s.shares < 1000, '500 to 999',
'1,000 or more') AS size_bucket,
count() AS fills_count,
round(1000 * avg(s.taker_side * (s.px - s.mid_at_fill)), 2) AS edge_at_fill_mils,
round(1000 * avg(s.taker_side * (s.px - f.mid)), 2) AS edge_after_60s_mils
FROM (SELECT *, toUInt32(ts + 60) AS future_ts FROM fills) AS s
INNER JOIN qs AS f ON f.ts = s.future_ts
GROUP BY size_bucket
ORDER BY min(s.shares)100 shares-এর কম fills প্রতি শেয়ারে 19.47 mils credit দিয়ে শুরু হয় এবং 1 minute পরে সেগুলোর মূল্য থাকে 15.22 mils। 1,000 shares বা তার বেশি print 36.26 mils দিয়ে শুরু হয় এবং একই সময়সীমায় 21.34 mils মূল্য ধরে রাখে। Instrument একই, 3 ঘণ্টাও একই, কিন্তু প্রতি শেয়ারের economics আলাদা। সবচেয়ে বড় order-গুলো প্রায়ই public queue পুরোপুরি এড়িয়ে চলে, আর block trade-এর উদ্দেশ্যই হলো এটি করা।
Inventory risk: যে position সময়মতো hedge করা যায় না
Markout horizon একই সঙ্গে একটি clock। কোনো market maker bid-এ 5,000 shares কিনলে তার কাছে 5,000 shares-এর position থাকে। Position hedge বা বিক্রি না হওয়া পর্যন্ত পরের মুহূর্তে দাম যা করবে, তার প্রভাব position-টির ওপর পড়বে। Hedging খুব কমই তাৎক্ষণিক হয়। একটি single-stock position correlated ETF বা options position দিয়ে offset করা যেতে পারে, আর প্রতিটিরই পার করার জন্য নিজস্ব spread থাকে। Inventory risk হলো ওই সময়সীমার মধ্যে দামের সম্ভাব্য ওঠানামার পরিমাণ, এবং যেকোনো নামের ক্ষেত্রে এটি একইভাবে মাপা হয়। সাধারণত পরের 1 minute-এ এবং পরের 1 hour-এ দাম কতটা এগোয়?
প্রতিটি সংখ্যার পেছনের সঠিক SQL
WITH
bars AS (
SELECT ticker, window_start,
toDate(toTimeZone(window_start, 'America/New_York')) AS et_date,
toFloat64(close) AS px
FROM global_markets.delayed_stocks_minute_aggs
WHERE ticker IN ('SPY', 'NVDA')
AND window_start >= '2026-05-01 00:00:00'
AND window_start < '2026-06-01 00:00:00'
AND transactions >= 50
AND close > 0
),
starts AS (
SELECT ticker, et_date, px, mins,
window_start + toIntervalMinute(mins) AS future_start
FROM (SELECT *, arrayJoin([1, 2, 5, 15, 30, 60]) AS mins FROM bars)
)
SELECT
concat(toString(s.mins), ' min') AS hold_horizon,
round(avgIf(abs(f.px / s.px - 1) * 10000, s.ticker = 'SPY'), 1) AS spy_drift_bps,
round(avgIf(abs(f.px / s.px - 1) * 10000, s.ticker = 'NVDA'), 1) AS nvda_drift_bps
FROM starts AS s
INNER JOIN bars AS f
ON f.ticker = s.ticker AND f.et_date = s.et_date AND f.window_start = s.future_start
GROUP BY s.mins
HAVING countIf(s.ticker = 'SPY') > 0 AND countIf(s.ticker = 'NVDA') > 0
ORDER BY s.minsMay 2026 জুড়ে SPY-এর 1 minute-এ average absolute move ছিল 1.9 basis points; 1 basis point হলো 1 percent-এর একশ ভাগের এক ভাগ। একই 1 minute-এ NVDA-এর পরিমাপ ছিল 5.5। সময়সীমা 1 hour করলে দুটি figure হয় 14.1 এবং 40.4। যে market maker 1 minute-এর মধ্যে position flatten করতে পারেন, তিনি প্রথম জোড়ার ঝুঁকি বহন করেন। যে market maker 1 hour ধরে রাখেন, তিনি দ্বিতীয় জোড়ার ঝুঁকি বহন করেন। দুই ক্ষেত্রেই fill-এর সময় সংগৃহীত credit একই।
কেন queue-এর পেছনে market makers অর্থ হারান
Exchange-গুলো একই দামে resting order মিলিয়ে দেয় arrival order অনুযায়ী: আগে price, পরে time। bid-এ 40,000 shares-এর queue-এর শেষে থাকা কোনো order-কে তার আগে থাকা 40,000 shares clear হওয়া পর্যন্ত অপেক্ষা করতে হয়। আর queue position অনুমান করা নিজেই একটি আলাদা discipline।
জটিলতা হলো clear হওয়ার অর্থ কী। Queue দুটি উপায়ে খালি হয়। Sellers bid-এ আঘাত করতে করতে level পুরোপুরি শেষ করে দিতে পারেন, অথবা price level-এর নিচে নেমে level-টিকে পেছনে ফেলে যেতে পারে। Queue-এর সামনের দিকে থাকা order দুটি পথেই অংশ নেয়। পেছনে থাকা order মূলত দ্বিতীয় পথে fill হয়, যখন level-টি পুরোনো price হতে যাচ্ছে। দুই market maker একই instrument একই দামে trade করেও ভিন্ন পরিমাণ spread ধরে রাখতে পারেন। Quote করা spread-এ queue slot কখনও দেখা যায় না, কারণ দুই market maker একই price quote করেছেন। এটি markout curve-এ দেখা যায়।
Quote চওড়া করা কেন বিনামূল্যের সমাধান নয়
খারাপ markout curve-এর স্পষ্ট সমাধান হলো আরও চওড়া quote করা। চওড়া quote প্রতি fill-এ বেশি আয় করে, কিন্তু কম fills পায়। এই trade-এর দুই দিকই একই দিনের prints-এ থাকে, midpoint থেকে প্রতিটি print কত দূরে হয়েছে সেই অনুযায়ী সাজানো।
প্রতিটি সংখ্যার পেছনের সঠিক SQL
WITH
qs AS (
SELECT toUnixTimestamp(toDateTime(sip_timestamp)) AS ts,
avg((toFloat64(bid_price) + toFloat64(ask_price)) / 2) AS mid
FROM global_markets.cache_stocks_quotes
WHERE ticker = 'AAPL'
AND sip_timestamp >= '2026-05-14 14:00:00'
AND sip_timestamp < '2026-05-14 17:06:00'
AND bid_price > 0 AND ask_price > bid_price
GROUP BY ts
),
fills AS (
SELECT t.ts AS ts, t.px AS px, t.shares AS shares, q.mid AS mid_at_fill,
if(t.px > q.mid, 1, -1) AS taker_side
FROM (
SELECT toUnixTimestamp(toDateTime(sip_timestamp)) AS ts,
toFloat64(price) AS px, toUInt64(size) AS shares
FROM global_markets.stocks_trades
WHERE ticker = 'AAPL'
AND sip_timestamp >= '2026-05-14 14:00:00'
AND sip_timestamp < '2026-05-14 17:00:00'
AND size > 0
) AS t
INNER JOIN qs AS q ON q.ts = t.ts
WHERE t.px != q.mid AND abs(t.px / q.mid - 1) < 0.02
)
SELECT
multiIf(s.cents <= 0.5, '0.5 cents or less',
s.cents <= 1.0, '0.5 to 1 cent',
s.cents <= 2.0, '1 to 2 cents',
'over 2 cents') AS distance_from_mid,
round(100 * sum(s.shares) / sum(sum(s.shares)) OVER (), 2) AS share_of_volume_pct,
round(1000 * avg(s.taker_side * (s.px - f.mid)), 2) AS edge_after_60s_mils
FROM (
SELECT *, toUInt32(ts + 60) AS future_ts, abs(px - mid_at_fill) * 100 AS cents
FROM fills
) AS s
INNER JOIN qs AS f ON f.ts = s.future_ts
GROUP BY distance_from_mid
ORDER BY min(s.cents)Midpoint-এর অর্ধেক cent-এর মধ্যে থাকা prints এই সময়সীমার shares-এর 27.58 percent ছিল; 1 minute পরে সেগুলোর মূল্য ছিল 0.95 mils per share। Midpoint থেকে 2 cents-এর বেশি দূরে হওয়া prints shares-এর 33.19 percent ছিল, এবং তাদের মূল্য ছিল 46.86 mils। Midpoint থেকে দূরে posted quote দিনের volume-এর ছোট অংশের কাছে পৌঁছায়।
Quote পেছনে সরার প্রথম খরচ হলো fill rate কমে যাওয়া। দ্বিতীয় খরচ হলো exchange rebate, কারণ অনেক venue fill হওয়া প্রতি share-এর জন্য market maker-কে অর্থ দেয়, আর সেই আয় quote-এর width-এর বদলে shares-এর সংখ্যার সঙ্গে বাড়ে। Rebate rate নির্ধারণকারী volume tier মাসিক হিসাবে গণনা করা হয়। তাই কোনো quiet month-এর কারণে পরের মাসে প্রতিটি fill-এর মূল্য পুনর্নির্ধারিত হয়। Queue slot ছেড়ে দেওয়া শেষ খরচ। বের হওয়ার সময় এই খরচ দিতে হয়, এবং ফিরে আসার সময় queue-এর পেছনে গিয়ে আবার দিতে হয়। প্রতিটি market maker এই curve-এর কোনো না কোনো স্থানে থাকেন। যারা নিজেদের markout সবচেয়ে নির্ভুলভাবে মাপেন, তারা touch-এর সবচেয়ে কাছে থেকেও credit ধরে রাখতে পারেন। এই measurement-ই সবচেয়ে বড় market makers-দের রক্ষিত edge।
প্রায়শই জিজ্ঞাসিত প্রশ্ন
Market makers কি individual trade-এ অর্থ হারান?
নিয়মিতই হারান। Making book হলো ছোট লাভ ও ছোট ক্ষতির একটি distribution। দাম নড়ার ঠিক আগের মুহূর্তগুলোতে losing fills বেশি জমা হয়। ব্যবসাটি নির্ভর করে millions of fills-এর ওপর হিসাব করা গড় ফলের ওপর।
Trading-এ markout কী?
Markout হলো fill-এর পর নির্দিষ্ট সময়সীমায় market price-এর পরিবর্তন, যা কোনো এক side-এর দৃষ্টিকোণ থেকে sign করা হয়। Positive number মানে সেই side লাভ করেছে। Equities desk markout quote করে mils per share-এ, আর options desk quote করে ticks per contract-এ।
Toxic order flow বলতে কী বোঝায়?
এটি এমন order flow বোঝায়, যার markout curve সেটি fill করা market maker-এর বিপরীতে ধারাবাহিকভাবে ঢালু। অর্থাৎ প্রতিটি fill-এর পর price market maker-এর বিপরীত দিকে চলতে থাকে। এই label একটি order stream-এর statistical property। কোনো একক trader সম্পর্কে এটি কোনো বিচার নয়।
Market makers quote তুলে না নিয়ে spread চওড়া করেন কেন?
চওড়া quote market maker-কে এমন একটি price-এ market-এ রাখে, যা খারাপ markout curve-এর খরচ পুষিয়ে দেয়। Quote তুলে নিলে কোনো আয় হয় না এবং queue position-ও হারাতে হয়। Desk-গুলো দুটি কাজই করে। সিদ্ধান্ত নির্ভর করে quote কতক্ষণ stale থাকার সম্ভাবনা আছে তার ওপর।
Adverse selection কীভাবে মাপা হয়?
Markout দিয়ে। Market maker কোন side-এ ছিলেন, সেই অনুযায়ী প্রতিটি fill sign করতে হয়। এরপর নির্দিষ্ট horizon-এ midpoint-এর পরিবর্তনের গড় নিতে হয়। Fill-এর সময়ের credit এবং প্রতিটি horizon-এ fill-এর মূল্যের ব্যবধানই adverse selection cost। এটি spread-এর মতো একই এককে প্রকাশ করা হয়।
এই সংখ্যাগুলো কীভাবে তৈরি করা হয়েছে
প্রতিটি AAPL panel দুটি public record ব্যবহার করে: trade tape এবং quote tape। May 14, 2026-এ 14:00 থেকে 17:00 UTC-এর মধ্যে হওয়া প্রতিটি print যে সেকেন্ডে হয়েছে, সেই সেকেন্ডের average national best bid and offer midpoint-এর সঙ্গে match করা হয়েছে এবং sign করা হয়েছে। Midpoint-এর ওপরে হওয়া print taker buy হিসেবে গণ্য হয়েছে, ফলে market maker sell side-এ ছিলেন। Midpoint-এ ঠিক হওয়া print-এর কোনো side নেই, তাই সেগুলো বাদ দেওয়া হয়েছে। Midpoint থেকে 2 percent-এর বেশি দূরে থাকা print-ও বাদ দেওয়া হয়েছে। Bid offer-এর সমান বা offer-এর চেয়ে বেশি হওয়া quote record বাদ দেওয়া হয়েছে, কারণ locked or crossed market-এ ব্যবহারযোগ্য midpoint থাকে না।
Second-level matching fill-এর microsecond-এ prevailing quote-এর আনুমানিক হিসাব দেয় এবং দ্রুততম update-গুলো মসৃণ করে। Horizon price একই second-level midpoint থেকে নেওয়া হয়েছে। Inventory panel-এ 1 minute bar ব্যবহার করা হয়েছে এবং অন্তত 50টি print থাকা bar-গুলোই রাখা হয়েছে। এতে sample দিনের সবচেয়ে সক্রিয় সময়গুলোর দিকে কেন্দ্রীভূত হয়।
এখানকার প্রতিটি panel-এ সেটি তৈরি করা SQL দেওয়া আছে। ফলে markout-এর হিসাব line by line পরীক্ষা করা যায়। অন্য কোনো নাম বা দিনের জন্য curve পুনর্গঠন করতে Strasmore terminal-এ plain English-এ অনুরোধ করুন।