درس 7: فهرستها و نگاشتها
مقدارهای زیادی را در آرایه یا نگاشت (map) نگه دارید: پنجرهای از کندلهای اخیر، حلقه روی عضوها، میانه و صدک، و شمارش بر اساس کلید.
درس 7 از 18. تاریخچه با [n] هر بار یک مقدار میدهد. وقتی به چند مقدار با هم نیاز دارید، مثلاً دامنهٔ بیست کندل آخر برای پیدا کردن وسط آنها، آنها را در یک آرایه (فهرستی مرتب) یا یک نگاشت (map) (مقدارهایی که زیر کلیدها نگه داشته میشوند) بگذارید.
پنجرهای از مقدارهای اخیر#
indicator "Last closes"
edition = 1
display = price
input size: int = 20, name = "Window size", min = 2, max = 500
state window: array<float> = array<float>()
window.push(close)
if window.size() > size
window.shift()
plot(window.avg(), name = "Average of the window", color = color.orange)
plot(window.max(), name = "Highest close", color = color.green)
plot(window.min(), name = "Lowest close", color = color.red)state window: array<float> = array<float>()یک بار آرایهای خالی از عدد میسازد و آن را از کندلی به کندل بعد نگه میدارد.window.push(close)قیمت بستهشدن همین کندل را به انتهای آرایه اضافه میکند. وقتی پنجره بیش ازsizeعضو داشته باشد،window.shift()قدیمیترین عضو را بیرون میاندازد..size()،.avg()،.max()و.min()کل آرایه را میخوانند..at(0)قدیمیترین عضو است و.last()جدیدترین؛ شمارهها از 0 شمرده میشوند.
گشتن در عضوها#
for x in window به ترتیب به همهٔ عضوها سر میزند. این اسکریپت میشمارد چند قیمت بستهشدن در پنجره بالای میانگینشان قرار دارند:
indicator "Share above the average"
edition = 1
display = pane
input size: int = 20, name = "Window size", min = 2, max = 500
state window: array<float> = array<float>()
window.push(close)
if window.size() > size
window.shift()
let average = window.avg()
mut above = 0
for x in window
if x > average
above += 1
plot(above / window.size() * 100, name = "Closes above the average, %", color = color.purple)
level(50, name = "Half", color = color.gray, style = dashed)mut above = 0 در هر کندل از نو شروع میشود، پس شمارش هر بار تازه انجام میشود. for (i, x) in window شمارهٔ i را هم میدهد.
وسط یک پنجره#
آرایه میتواند عضوهایش را مرتب کند تا میانه یا صدک را پیدا کند. اینجا پنجره دامنهٔ کندلها را نگه میدارد و اسکریپت دامنهٔ معمول و یک دامنهٔ بزرگ را نشان میدهد:
indicator "Typical range"
edition = 1
display = pane
input size: int = 50, name = "Window size", min = 5, max = 500
state ranges: array<float> = array<float>()
ranges.push(high - low)
if ranges.size() > size
ranges.shift()
plot(high - low, name = "Range", style = columns, color = color.gray)
plot(ranges.median(), name = "Median range", color = color.blue)
plot(ranges.percentile(80), name = "80th percentile", color = color.orange)ranges.median() مقدار وسط پنجره است و ranges.percentile(80) مقداری که 80 درصد عضوها پایینتر از آناند. ستونی که بالای خط نارنجی برود، کندلی است که از چهار کندل از هر پنج کندل پنجره پهنتر است.
مقدارها زیر کلیدها#
نگاشت (map) یک مقدار را زیر یک کلید نگه میدارد. این یکی برای هر ساعت روز، مجموع دامنهٔ کندلهای آن ساعت و تعدادشان را نگه میدارد و میانگین دامنهٔ ساعت فعلی را رسم میکند:
indicator "Range by hour"
edition = 1
display = pane
state totals: map<int, float> = map<int, float>()
state counts: map<int, int> = map<int, int>()
let hour = clock.hour_of(bar.time, zone = "UTC")
totals.set(hour, (totals.at(hour) ?? 0) + (high - low))
counts.set(hour, (counts.at(hour) ?? 0) + 1)
mut widest_hour = 0
mut widest = 0.0
for key in totals.keys()
let average = totals.at(key) / counts.at(key)
if average > widest
widest = average
widest_hour = key
plot(totals.at(hour) / counts.at(hour), name = "Average range of this hour", color = color.blue)
plot(widest_hour, name = "Hour with the widest bars (UTC)", display = none)totals.set(key, value)مقداری را نگه میدارد؛totals.at(key)آن را میخواند و تا وقتی کلید وجود نداردnaمیدهد، پس?? 0ساعت تازه را از 0 شروع میکند.totals.keys()آرایهای از کلیدهاست، پس یک حلقهٔforمیتواند در آنها بگردد.display = noneخط آخر را از روی نمودار برمیدارد: اسکریپت مقدار را باز هم حساب میکند، اما رسمش نمیکند.
آن را روی نمودار درونروزی به کار ببرید: روی نمودار روزانه همهٔ کندلها یک ساعت دارند.
اشتباهی که باید از آن دوری کرد#
کروشه بعد از یک نام همیشه یعنی تاریخچه، هیچوقت «عضوِ شمارهٔ فلان» نیست: window[1] کل آرایه است، همانطور که یک کندل قبل بود. بررسیکننده آن را نمیپذیرد و میگوید window.at(1) بنویسید:
indicator "Brackets on an array"
edition = 1
display = price
state window: array<float> = array<float>()
window.push(close)
if window.size() > 10
window.shift()
plot(window[1], name = "Second item")آرایه یا نگاشت حداکثر 100,000 عضو نگه میدارد؛ بیشتر از آن، اسکریپت با E-LIMIT-ITEMS متوقف میشود. پنجرهای که قدیمیترین عضوش را با shift() بیرون میاندازد هیچوقت به این سقف نزدیک نمیشود. خواندن .at(i) بیرون از آرایه هم اسکریپت را متوقف میکند، پس اول .size() را بررسی کنید.
امتحان کنید#
- در «Last closes»، در
window.push(...)به جایcloseبنویسیدhigh - low: حالا خطها دامنهٔ کندلها را نشان میدهند، نه قیمت را (باdisplay = paneاسکریپت را به پنل جدا ببرید). - در «Share above the average»،
x > averageرا بهx > closeتغییر دهید: خط سهمی از پنجره را نشان میدهد که بالای قیمت بستهشدن فعلی است. - در «Typical range»،
ranges.percentile(95)را امتحان کنید: خط نارنجی بالا میرود و ستونهای کمتری از آن رد میشوند. - در «Range by hour»،
zone = "Europe/London"را به کار ببرید: ساعتها به وقت لندن شمرده میشوند.
نقطهٔ بررسی#
- میتوانید پنجرهای غلتان از مقدارها را در یک آرایهٔ
stateباpushوshiftنگه دارید. - میتوانید با
for x in ...در آرایه بگردید و عضوهای تکی را با.at(i)بخوانید. - میتوانید میانه و صدک یک پنجره را پیدا کنید.
- میتوانید در یک نگاشت مقدارها را بر اساس کلید بشمارید و جمع بزنید، و میدانید که
.at(key)برای کلید ناموجودnaمیدهد.