مؤشر On Balance Volume: الصيغة والإعدادات وطريقة القراءة
مؤشر On Balance Volume، الذي نشره Joseph Granville عام 1963، يضيف حجم الشمعة كاملًا إلى مجموع تراكمي عندما يرتفع الإغلاق ويطرحه عندما ينخفض. أما الإغلاق غير المتغيّر فيترك المجموع كما هو تمامًا.
Senzoukria · المؤشرات · Updated September 2026
On Balance Volume — الحجم, في لوحة مستقلة أسفل الرسم.
ما الذي يقيسه On Balance Volume
يتحدّد الاتجاه بمقارنة صارمة بين إغلاقين متتاليين: الأعلى يضيف، والأدنى يطرح، والمساوي لا يفعل شيئًا، فلا تُحتسب شموع الدوجي صاعدة أبدًا. يُوقَّع حجم كل شمعة بكامله؛ فالمؤشر لا يفرّق بين إغلاق أعلى بتيك واحد وإغلاق أعلى بثلاثين تيكًا. يبدأ Senzoukria السلسلة من 0 عند أول شمعة محمّلة، ما يجعل الخط المرسوم قابلًا للتكرار بينما يظل مستواه المطلق بلا معنى. التراكم متصل ولا يُصفَّر عند افتتاح 17:00 CT، وهي نقطة ارتكاز محجوزة للمقاييس المبنية على الجلسة مثل الدلتا التراكمية.
الصيغة كما هي منفَّذة في الكود
هذا ليس التعريف الشائع في مصادر أخرى، بل ما يحسبه الكود المنشور فعليًا، موثَّقًا بجانب التنفيذ:
Période entière ≥ `min` depuis les params (garde-fou UI). */ function intParam( params: Record<string, unknown>, key: string, fallback: number, min = 1, ): number { return Math.max(min, Math.floor(numParam(params, key, fallback))); } function toPoints( bars: readonly FootprintBar[], values: ReadonlyArray<number | null>, ): SeriesPoint[] { return bars.map((b, i) => ({ time: b.bucketTsNs, value: values[i] ?? null })); } /** Points d'histogramme : `f` rend `null` quand la barre n'a pas d'information — la barre n'émet alors PAS de point (contrat `HistogramPoint` : pas de trou, pas de valeur inventée). */ function histPoints( bars: readonly FootprintBar[], f: (bar: FootprintBar, i: number) => number | null, ): HistogramPoint[] { const out: HistogramPoint[] = []; for (let i = 0; i < bars.length; i++) { const v = f(bars[i], i); if (v !== null) out.push({ time: bars[i].bucketTsNs, value: v }); } return out; } function histOut( points: HistogramPoint[], positiveColor: string, negativeColor: string, ): SeriesOutput { return { shape: "histogram", points, positiveColor, negativeColor }; } /** SMA N sur série à trous : null dès qu'UNE valeur de la fenêtre est null — moyenner autour d'un trou mentirait sur la période effective (même règle que `smaNullable` de momentum.ts). */ function smaNullable( values: ReadonlyArray<number | null>, period: number, ): Array<number | null> { const n = Math.max(1, Math.floor(period)); const out: Array<number | null> = new Array<number | null>(values.length).fill(null); for (let i = n - 1; i < values.length; i++) { let sum = 0; let ok = true; for (let j = i - n + 1; j <= i; j++) { const v = values[j]; if (v === null) { ok = false; break; } sum += v; } if (ok) out[i] = sum / n; } return out; } /** EMA N par segment de valeurs définies consécutives. Un trou reste null et réinitialise uniquement la graine suivante : les valeurs antérieures sont conservées. Chaque reprise attend N valeurs pour sa SMA initiale, puis suit la même récurrence que `emaSeries`, sans zéro synthétique. */ function segmentedEma( values: ReadonlyArray<number | null>, period: number, ): Array<number | null> { const n = Math.max(1, Math.floor(period)); const alpha = 2 / (n + 1); const out: Array<number | null> = new Array<number | null>(values.length).fill(null); let count = 0; let sum = 0; let ema = 0; for (let i = 0; i < values.length; i++) { const v = values[i]; if (v === null) { count = 0; sum = 0; continue; } if (count < n) { sum += v; count += 1; if (count < n) continue; ema = sum / n; } else { ema += alpha * (v - ema); } out[i] = ema; } return out; } /** Money Flow Volume de Chaikin pour UNE barre : MFM = ((close − low) − (high − close)) / (high − low) ∈ [−1, +1] MFV = MFM × volume MFM est la position du close dans le range, recentrée : +1 = close au plus haut (toute la barre a été achetée), −1 = close au plus bas. Range NUL (high = low) → `null` : le multiplicateur est un 0/0, la barre ne porte aucune information directionnelle. Les appelants décident quoi en faire — cumul → contribution 0 (cf. en-tête), non cumulé → pas de point. / function moneyFlowVolume(bar: FootprintBar): number | null { const range = bar.high - bar.low; if (!(range > 0)) return null; const mfm = (bar.close - bar.low - (bar.high - bar.close)) / range; return mfm * bar.totalVolume; } /** Ligne A/D (Chaikin) : cumul du Money Flow Volume depuis la première barre chargée. Barre à range nul → contribution 0 (exception documentée en en-tête : un accumulateur ne peut pas porter de trou). CONTINU — pas de reset session (l'A/D est une ligne d'accumulation de long terme). */ function accumDistValues(bars: readonly FootprintBar[]): number[] { const out: number[] = new Array<number>(bars.length); let running = 0; for (let i = 0; i < bars.length; i++) { running += moneyFlowVolume(bars[i]) ?? 0; out[i] = running; } return out; } /** VWMA N sur une fenêtre glissante : Σ(close·volume) / Σ(volume). Σvolume = 0 sur la fenêtre (barres placeholder sans trade) → null : 0/0 n'est pas « 0 ». Warm-up (< N barres) → null. Même formule que `vwma` (averages2.ts) — redéclarée ici plutôt que d'élargir la surface publique d'un autre fichier de famille (sa primitive n'est pas exportée). */ function vwmaSeries( bars: readonly FootprintBar[], period: number, ): Array<number | null> { const n = Math.max(1, Math.floor(period)); const out: Array<number | null> = new Array<number | null>(bars.length).fill(null); let sumPV = 0; let sumV = 0; for (let i = 0; i < bars.length; i++) { sumPV += bars[i].close * bars[i].totalVolume; sumV += bars[i].totalVolume; if (i >= n) { sumPV -= bars[i - n].close * bars[i - n].totalVolume; sumV -= bars[i - n].totalVolume; } if (i >= n - 1) out[i] = sumV > 0 ? sumPV / sumV : null; } return out; } /** Indices de volume de Fosback/Dysart (NVI / PVI) — même moteur, deux déclencheurs : index[0] = base index[i] = index[i−1] × (1 + (close[i] − close[i−1]) / close[i−1]) si `trigger(volume[i], volume[i−1])`, sinon index[i−1] NVI : trigger = volume EN BAISSE (Fosback — l'« argent malin » se positionne les jours calmes). PVI : trigger = volume EN HAUSSE (la foule). Volume ÉGAL → aucun des deux ne bouge (inégalités STRICTES, convention d'origine : une journée sans changement de participation n'est ni l'un ni l'autre). close[i−1] = 0 → contribution 0, l'indice est GELÉ (exception documentée en en-tête : le ratio n'existe pas, et un null perdrait l'ancrage de toute la suite de l'indice — un indice base 1000 sans ancrage ne vaut rien). / function volumeIndexValues( bars: readonly FootprintBar[], base: number, trigger: (vol: number, prevVol: number) => boolean, ): number[] { const out: number[] = new Array<number>(bars.length); let idx = base; for (let i = 0; i < bars.length; i++) { if (i > 0) { const prev = bars[i - 1]; const prevClose = prev.close; if (trigger(bars[i].totalVolume, prev.totalVolume) && prevClose !== 0) { idx *= 1 + (bars[i].close - prevClose) / prevClose; } } out[i] = idx; } return out; } // ── Defs ──────────────────────────────────────────────────────────────────── /** OBV — On Balance Volume (Granville, 1963) : OBV[0] = 0 (graine, cf. convention) OBV[i] = OBV[i−1] + volume[i] si close[i] > close[i−1] = OBV[i−1] − volume[i] si close[i] < close[i−1] = OBV[i−1] si close[i] = close[i−1] POURQUOI : la thèse de Granville est que le volume précède le prix. L'OBV signe le volume ENTIER de la barre par la direction du close — sa PENTE et ses divergences avec le prix sont l'information, jamais son niveau absolu. Convention GRAINE : OBV[0] = 0. L'indicateur n'a pas d'origine absolue (Granville lui-même part d'un nombre arbitraire) ; ancrer à 0 sur la première barre CHARGÉE rend la série reproductible et lisible. Corollaire assumé : charger plus d'historique décale toute la courbe — c'est vrai de tout OBV, ATAS et TradingView compris. Convention ÉGALITÉ : close inchangé → OBV inchangé (règle de Granville, inégalités STRICTES — pas de « ≥ » qui compterait les dojis comme haussiers). CONTINU : pas de reset de session — l'ancrage 17:00 CT ne concerne que les cumuls orderflow type CVD, l'OBV est une accumulation de long terme.
كيف تقرأه
- زعم Granville أن الحجم يسبق السعر؛ أيًّا كان رأيك في ذلك، فالمحتوى القابل للاستخدام هو ميل الخط واختلافاته مع السعر، لا مستواه أبدًا.
- سلسلة من القيعان الأعلى في OBV تحت سعر عرضي تعني أن الإغلاقات الهابطة جاءت بحجم أخف من الإغلاقات الصاعدة خلال تلك الفترة.
- حين يسجّل السعر قمة جديدة ولا يسجّلها OBV، فإن الإغلاقات الصاعدة خلف تلك القمة حملت حجمًا أقل من سابقاتها؛ هذه حقيقة عن تلك الشموع، لا إشارة.
- بما أن تحميل مزيد من السجل يزيح المنحنى كله، فلا تبنِ شيئًا على عتبة لـ OBV؛ ابنِ على الشكل.
- في العقود الآجلة داخل اليوم، قارن OBV بالدلتا التراكمية: OBV يوقّع الحجم باتجاه الإغلاق، والدلتا توقّعه بجانب المُبادِر، ويختلفان تحديدًا حيث حدث الامتصاص.
المعاملات والقيم الافتراضية
التنعيم افتراضيًا 1، فيبقى الخط التراكمي الخام دون مساس؛ والقيم حتى 200 تطبّق تنعيمًا لاحقًا يُسهّل رؤية الميل على المدى الطويل بينما يخفي الشموع المنفردة التي أنتجته. اللون الافتراضي أزرق (#2962ff).
| المعامل | النوع | القيمة الافتراضية | المدى |
|---|---|---|---|
| Smoothing | number | 1 | 1 – 200 |
ما لا يُظهره
OBV مبدأ «كل شيء أو لا شيء»: تقدّم بتيك واحد وتقدّم كبير يساهمان بالقدر نفسه، ما يجعل الخط متقطّعًا في الأدوات التي كثيرًا ما تُغلق قرب مستوى الإغلاق السابق. لا يستخدم سوى الإغلاق، فيبقى كل ما جرى داخل الشمعة غير مرئي، بما في ذلك الامتصاص وجانب المُبادِر. البداية من الصفر تجعل القيم المطلقة بلا معنى وغير قابلة للمقارنة بين الرسوم البيانية أو أعماق السجل، وهي خاصية تشترك فيها كل تطبيقات OBV، بما فيها تلك الموجودة في ATAS وTradingView. الإغلاقات المتساوية تجمّد الخط، لذا فإن بيانات الأسعار المقرَّبة بشدة أو منخفضة الدقة تسطّحه لأسباب آلية.
مؤشرات ذات صلة
- Volume — الحجم
- Buy/Sell Volume — الحجم
- Average Trade Size — الحجم
- Volume ROC % — الحجم
- Relative Volume — الحجم
- Trade Count — الحجم
هذه الصفحة بلغات أخرى
Frequently asked questions
- كيف يُحسب مؤشر On Balance Volume؟
- انطلاقًا من قيمة ابتدائية، يُضاف حجم كل شمعة كاملًا حين يكون إغلاقها أعلى من الإغلاق السابق، ويُطرح حين يكون أدنى. وعندما يتساوى الإغلاقان يبقى المجموع دون تغيير. في Senzoukria القيمة الابتدائية هي 0 عند أول شمعة محمّلة في الرسم البياني.
- هل يُعاد ضبط On Balance Volume عند افتتاح الجلسة؟
- لا. يعمل OBV بشكل متصل عبر الجلسات، إذ صمّمه Granville كتراكم طويل المدى. نقطة ارتكاز الجلسة عند 17:00 CT في التطبيق تخصّ التراكمات المبنية على الجلسة مثل الدلتا التراكمية أو حجم الجلسة، لا OBV.
- ما الفرق بين OBV والدلتا التراكمية؟
- يوقّع OBV حجم الشمعة باتجاه إغلاقها، فلا يعتمد إلا على بيانات OHLC. أما الدلتا التراكمية فتوقّع الحجم بجانب المُبادِر في كل صفقة وتتطلب تصنيف Bid/Ask من مصدر البيانات. ويفترقان حيث لم يحرّك الحجمُ العدواني الإغلاقَ، وهذه بصمة الامتصاص.