FMZ Quant এর পাইন ল্যাঙ্গুয়েজ প্রারম্ভিক টিউটোরিয়াল

লেখক:লিডিয়া, সৃষ্টিঃ ২০২২-০৯-২৩ 15:23:34, আপডেটঃ ২০২৪-০২-২৭ ১৬ঃ৪৭ঃ৪১

historical value reference করা যেতে পারে। সুতরাং আমরা দেখতে পাচ্ছি যে আঁকা তিনটি লাইন a, b, এবং c-এ, লাইন b লাইন a-এর চেয়ে এক BAR ধীর এবং লাইন c লাইন b-এর চেয়ে এক BAR ধীর। লাইন c লাইন a-এর চেয়ে ২ BAR ধীর।

আমরা চার্টটি খুব বাম দিকে টানতে পারি এবং পর্যবেক্ষণ করতে পারি যে প্রথম কে-লাইনে, বি এবং সি এর উভয় মানই শূন্য (এনএ) । এর কারণ হ'ল যখন স্ক্রিপ্টটি প্রথম কে-লাইন BAR এ কার্যকর করা হয়, তখন এটি বিদ্যমান নেই যখন এক বা দুটি সময়ের historicalতিহাসিক মানের উল্লেখ করা হয়, যা বিদ্যমান নেই। অতএব, ইতিহাসের ডেটাতে রেফারেন্সের ফলে শূন্য মান হবে কিনা তা পরীক্ষা করার জন্য কৌশল লেখার সময় আমাদের সাবধান হওয়া দরকার। যদি শূন্য মানটি অবহেলা ব্যবহার করা হয় তবে এটি গণনার পার্থক্যের একটি সিরিজ সৃষ্টি করবে এবং এমনকি রিয়েল-টাইম BAR কে প্রভাবিত করতে পারে। সাধারণত আমরা অন্তর্নির্মিত ফাংশনগুলি ব্যবহার করবna, nzকোড বিচার করতে (আসলে, আমরাও সম্মুখীন হয়েছেnz, ```na`` আমাদের পূর্ববর্তী ভিডিওতে, আপনি কি মনে রাখবেন কোন অধ্যায় এটি হয়?

close > nz(close[1], open)    // When referencing the historical value of the previous BAR of the close built-in variable, if it does not exist, the open built-in variable is used

এটি শূন্য মান (na) এর সম্ভাব্য উল্লেখগুলি পরিচালনা করার একটি উপায়।

অপারেটরের অগ্রাধিকার

আমরা পাইন ভাষায় অনেক অপারেটর শিখেছি। এই অপারেটরগুলি অপারেন্ডগুলির সাথে বিভিন্ন সংমিশ্রণের মাধ্যমে অভিব্যক্তি গঠন করে। সুতরাং অভিব্যক্তিতে মূল্যায়ন করার সময় এই অপারেশনগুলির অগ্রাধিকার কী? ঠিক যেমন আমরা স্কুলে শিখেছি অ্যারিথেটিক্স, গুণ এবং বিভাজন প্রথমে গণনা করা হয়, তারপরে যোগ এবং বিয়োগ। পাইন ভাষায় অভিব্যক্তিগুলির জন্যও একই কথা।

অগ্রাধিকার অপারেটর
9 []
8 +-এবংnotইউনারি অপারেটর
7 */%
6 +-বাইনারি অপারেটর
5 ><>=<=
4 ==!=
3 and
2 or
1 ?:

উচ্চ অগ্রাধিকার এক্সপ্রেশন প্রথম গণনা করা হয়, এবং যদি অগ্রাধিকার একই হয়, এটি বাম থেকে ডানে মূল্যায়ন করা হয়. আপনি যদি একটি নির্দিষ্ট অংশ প্রথম মূল্যায়ন করতে বাধ্য করতে চান, আপনি ব্যবহার করতে পারেন()প্রথম অংশটি মূল্যায়ন করার জন্য অভিব্যক্তিটি আবৃত করতে।

ভেরিয়েবল

ভেরিয়েবল ডিক্লেয়ারেশন

আমরা আগেও marker এর ধারণাটি অধ্যয়ন করেছি, যা একটি ভেরিয়েবলের নাম হিসাবে ব্যবহৃত হয়, অর্থাৎ, একটি ভেরিয়েবল একটি চিহ্নিতকারী যা একটি মান ধারণ করে। সুতরাং আমরা কীভাবে একটি ভেরিয়েবল ঘোষণা করব? ভেরিয়েবল ঘোষণা করার নিয়মগুলি কী?

  • ঘোষণার মোডঃ একটি ভেরিয়েবল ঘোষণার সময় প্রথম জিনিসটি লিখতে হবে declaration mode। ভেরিয়েবলগুলির জন্য তিনটি ঘোষণার মোড রয়েছেঃ

    1. কীওয়ার্ড ব্যবহার করুনvar.
    2. কীওয়ার্ড ব্যবহার করুনvarip.
    3. কিছুই লিখো না।

    দ্যvarএবংvaripমূলশব্দ আসলে আমাদের পূর্ববর্তী অধ্যায়ে অধ্যয়ন করা হয়েছেAssignment Operators, তাই আমরা এখানে বিস্তারিত যাব না. যদি পরিবর্তনশীল ঘোষণার মোডের জন্য কিছুই লেখা না হয়, যেমন বিবৃতিঃi = 1, যেমনটি আমরা আগে উল্লেখ করেছি, এই ধরনের একটি ভেরিয়েবল ঘোষিত এবং বরাদ্দ করা হয় প্রতিটি কে-লাইন BAR এ।

  • প্রকার এফএমজেডের পাইন ভাষা টাইপ সম্পর্কে কঠোর নয়, এবং এটি সাধারণত বাদ দেওয়া যেতে পারে। তবে, ট্রেডিং ভিউতে স্ক্রিপ্টিং কৌশলটির সাথে সামঞ্জস্যপূর্ণ হওয়ার জন্য, ভেরিয়েবলগুলিও টাইপগুলির সাথে ঘোষণা করা যেতে পারে। উদাহরণস্বরূপঃ

    int i = 0 
    float f = 1.1
    

    ট্রেডিং ভিউতে টাইপ প্রয়োজনীয়তা বেশ কঠোর এবং ট্রেডিং ভিউতে নিম্নলিখিত কোডটি ব্যবহার করা হলে একটি ত্রুটি রিপোর্ট করা হবেঃ

    baseLine0 = na          // compile time error!
    
  • মার্কার মার্কারগুলি ভেরিয়েবলের নাম। মার্কারগুলির নামকরণ পূর্ববর্তী অধ্যায়গুলিতে উল্লেখ করা হয়েছে, তাই আপনি এটি এখানে পর্যালোচনা করতে পারেনঃhttps://www.fmz.com/bbs-topic/9637#markers

সংক্ষেপে, একটি ভেরিয়েবল ঘোষণার জন্য লিখতে পারেনঃ

// [<declaration_mode>] [<type>] <marker> = value 
   declaration mode             type     marker      = value

এখানে অ্যাসাইনমেন্ট অপারেটর ব্যবহার করা হয়ঃ=যখন এটি ঘোষণা করা হয় তখন একটি ভেরিয়েবলকে একটি মান বরাদ্দ করে। বরাদ্দ করার সময় মানটি একটি স্ট্রিং, সংখ্যা, অভিব্যক্তি, ফাংশন কল,if, for, while, অথবাswitchএবং অন্যান্য কাঠামো (এই কাঠামোগত কীওয়ার্ড এবং বিবৃতি ব্যবহার পরবর্তী কোর্সে বিস্তারিতভাবে ব্যাখ্যা করা হবে। আসলে, আমরা সহজ শিখেছি যদি বিবৃতি পূর্ববর্তী কোর্সে কাজ এবং আপনি তাদের পর্যালোচনা করতে পারেন) ।

এখানে আমরা ইনপুট ফাংশন উপর ফোকাস, যা একটি ফাংশন যে আমরা ডিজাইন এবং কৌশল লেখার সময় প্রায়ই ব্যবহার করা হবে. এটি কৌশল ডিজাইন করার সময় একটি খুব সমালোচনামূলক ফাংশন.

ইনপুট ফাংশনঃ

input function, parameters: defval、title、tooltip、inline、group

এফএমজেডের ইনপুট ফাংশনটি ট্রেডিং ভিউ থেকে কিছুটা আলাদা, তবে এই ফাংশনটি কৌশল পরামিতিগুলির অ্যাসাইনমেন্ট ইনপুট হিসাবে ব্যবহৃত হয়। এফএমজেডের ইনপুট ফাংশনটির ব্যবহার বিস্তারিতভাবে চিত্রিত করার জন্য একটি উদাহরণ ব্যবহার করা যাকঃ

param1 = input(10, title="name of param1", tooltip="description for param1", group="group name A")
param2 = input("close", title="name of param2", tooltip="description for param2", group="group name A")
param3 = input(color.red, title="name of param3", tooltip="description for param3", group="group name B")
param4 = input(close, title="name of param4", tooltip="description for param4", group="group name B")
param5 = input(true, title="name of param5", tooltip="description for param5", group="group name C")

ma = ta.ema(param4, param1)
plot(ma, title=param2, color=param3, overlay=param5)

ইনপুট ফাংশনটি প্রায়শই তাদের ঘোষণার সময় ভেরিয়েবলগুলিতে মান নির্ধারণের জন্য ব্যবহৃত হয়। এফএমজেডের ইনপুট ফাংশনটি এফএমজেড কৌশল ইন্টারফেসে স্বয়ংক্রিয়ভাবে কৌশল পরামিতি সেট করার জন্য নিয়ন্ত্রণগুলি আঁকে। এফএমজেডে সমর্থিত নিয়ন্ত্রণগুলির মধ্যে বর্তমানে সংখ্যাসূচক ইনপুট বাক্স, পাঠ্য ইনপুট বাক্স, ড্রপ-ডাউন বাক্স এবং বুলিয়ান চেকবক্স অন্তর্ভুক্ত রয়েছে। এবং আপনি কৌশল পরামিতি গোষ্ঠীভুক্তকরণ সেট করতে পারেন, প্যারামিটার প্রম্পট পাঠ্য বার্তা এবং অন্যান্য ফাংশন সেট করতে পারেন।

img

আমরা ইনপুট ফাংশনের বেশ কয়েকটি প্রধান পরামিতি পরিচয় করিয়ে দিচ্ছিঃ

  • defval: ইনপুট ফাংশন দ্বারা সেট করা কৌশল প্যারামিটার বিকল্পগুলির জন্য ডিফল্ট মান, পাইন ভাষার অন্তর্নির্মিত ভেরিয়েবল, সংখ্যাসূচক মান এবং স্ট্রিং সমর্থন করে।
  • Title: লাইভ ট্রেডিং/ব্যাক টেস্টিং চলাকালীন কৌশল ইন্টারফেসে প্রদর্শিত কৌশলটির পরামিতির নাম।
  • টুলটিপঃ কৌশল পরামিতির জন্য টুলটিপ তথ্য, যখন মাউস কৌশল পরামিতির উপর ফ্লাশ করে, প্যারামিটার সেটিং এর টেক্সট তথ্য প্রদর্শিত হবে।
  • গ্রুপঃ কৌশল পরামিতি গ্রুপের নাম, যা কৌশল পরামিতিতে ব্যবহার করা যেতে পারে।

পৃথক ভেরিয়েবল ঘোষণা এবং বরাদ্দ ছাড়াও, একটি গ্রুপ ভেরিয়েবল ঘোষণা এবং পাইন ভাষায় তাদের বরাদ্দ করার একটি উপায় রয়েছেঃ

[Variable A, Variable B, Variable C] = function or structure, such as ```if```, ```for```, ```while``` or ```switch```

সবচেয়ে সাধারণ হল যখন আমরাta.macdMACD সূচক গণনা করার জন্য ফাংশন, যেহেতু MACD সূচক একটি মাল্টি-লাইন সূচক, তিন সেট তথ্য গণনা করা হয়। তাই এটি হিসাবে লেখা যেতে পারেঃ

[dif,dea,column] = ta.macd(close, 12, 26, 9)

plot(dif, title="dif")
plot(dea, title="dea")
plot(column, title="column", style=plot.style_histogram)

আমরা উপরের কোড ব্যবহার করে সহজেই MACD চার্ট আঁকতে পারি। কেবলমাত্র বিল্ট-ইন ফাংশনগুলি একাধিক ভেরিয়েবলগুলিতে ফিরে আসতে পারে না, তবে লিখিত কাস্টম ফাংশনগুলিও একাধিক ডেটাতে ফিরে আসতে পারে।

twoEMA(data, fastPeriod, slowPeriod) =>
    fast = ta.ema(data, fastPeriod)
    slow = ta.ema(data, slowPeriod)
    [fast, slow]

[ema10, ema20] = twoEMA(close, 10, 20)
plot(ema10, title="ema10", overlay=true)
plot(ema20, title="ema20", overlay=true)

একাধিক ভেরিয়েবল অ্যাসাইনমেন্ট হিসাবে যদি এবং অন্যান্য কাঠামো ব্যবহার করার লেখার পদ্ধতিও উপরের কাস্টম ফাংশনের অনুরূপ, এবং আপনি যদি আগ্রহী হন তবে আপনি এটি চেষ্টা করতে পারেন।

[ema10, ema20] = if true
    fast = ta.ema(close, 10)
    slow = ta.ema(close, 20)
    [fast, slow]

plot(ema10, title="ema10", color=color.fuchsia, overlay=true)
plot(ema20, title="ema20", color=color.aqua, overlay=true)

শর্ত গঠন

কিছু ফাংশন শর্তাধীন শাখার স্থানীয় কোড ব্লকে লিখতে পারে না, প্রধানত নিম্নলিখিত ফাংশনগুলি অন্তর্ভুক্ত করেঃ

বারকলার (), ফিল (), হ্লাইন (), ইন্ডিকেটর (), প্লট (), প্লটক্যান্ডেল (), প্লটচার (), প্লটশপ (), প্লটশপ ())

ট্রেডিং ভিউ ত্রুটিগুলির সাথে কম্পাইল করবে, এফএমজেড ততটা সীমাবদ্ধ নয়, তবে ট্রেডিং ভিউয়ের স্পেসিফিকেশনগুলি অনুসরণ করার পরামর্শ দেওয়া হয়। উদাহরণস্বরূপ, যদিও এটি এফএমজেডে কোনও ত্রুটি রিপোর্ট করে না, এটি সুপারিশ করা হয় না।

strategy("test", overlay=true)
if close > open 
    plot(close, title="close")
else 
    plot(open, title="open")

if বিবৃতি

ব্যাখ্যা উদাহরণঃ

var lineColor = na

n = if bar_index > 10 and bar_index <= 20
    lineColor := color.green
else if bar_index > 20 and bar_index <= 30
    lineColor := color.blue
else if bar_index > 30 and bar_index <= 40
    lineColor := color.orange
else if bar_index > 40
    lineColor := color.black
else 
    lineColor := color.red
    
plot(close, title="close", color=n, linewidth=5, overlay=true)
plotchar(true, title="bar_index", char=str.tostring(bar_index), location=location.abovebar, color=color.red, overlay=true)

মূল পয়েন্ট: বুল মান ফেরত যে রায় জন্য ব্যবহৃত অভিব্যক্তি. ইন্ডেন্টেশন লক্ষ্য করুন. সেখানে সর্বোচ্চ এক অন্য শাখা হতে পারে. যদি সব শাখা অভিব্যক্তি সত্য নয় এবং অন্য শাখা নেই, ফেরত না.

x = if close > open
    close
plot(x, title="x")

স্যুইচ বিবৃতি

সুইচ স্ট্র্যাটেকশনটি একটি শাখা কাঠামোগত স্ট্র্যাটেকশন, যা নির্দিষ্ট শর্ত অনুসারে কার্যকর করার জন্য বিভিন্ন পথ ডিজাইন করতে ব্যবহৃত হয়। সাধারণভাবে, সুইচ স্ট্র্যাটেকশনে নিম্নলিখিত মূল জ্ঞান পয়েন্ট রয়েছে।

  1. সুইচ স্ট্রেশন, if স্ট্রেশন এর মত, একটি মানও ফেরত দিতে পারে।
  2. অন্যান্য ভাষার সুইচ স্ট্রেশনগুলির বিপরীতে, যখন একটি সুইচ কনস্ট্রাক্ট কার্যকর করা হয়, তখন এর কোডের কেবলমাত্র একটি স্থানীয় ব্লক কার্যকর করা হয়, তাই বিরতি বিবৃতি অপ্রয়োজনীয় (যেমন, বিরতি মত কীওয়ার্ড লেখার প্রয়োজন নেই) ।
  3. সুইচের প্রতিটি শাখা একটি স্থানীয় কোড ব্লক লিখতে পারে, এই স্থানীয় কোড ব্লকের শেষ লাইনটি রিটার্ন মান (এটি মানগুলির একটি টিপল হতে পারে) । যদি শাখাযুক্ত স্থানীয় কোড ব্লকগুলির মধ্যে কোনওটিই কার্যকর করা না হয় তবে na প্রদান করে।
  4. সুইচ স্ট্রাকচারের এক্সপ্রেশনটি অবস্থান নির্ধারণ করে একটি স্ট্রিং, ভেরিয়েবল, এক্সপ্রেশন বা ফাংশন কল লিখতে পারে।
  5. স্যুইচ একটি রিটার্ন মান নির্দিষ্ট করতে দেয় যা স্ট্রাকচারে অন্য কোন ক্ষেত্রে চালানোর জন্য ব্যবহার করার জন্য ডিফল্ট মান হিসাবে কাজ করে।

স্যুইচ দুটি ফর্ম আছে, আসুন তাদের ব্যবহার বুঝতে উদাহরণ এক এক করে তাকান।

  1. switchএক্সপ্রেশন সহ - উদাহরণ ব্যাখ্যাঃ
// input.string: defval, title, options, tooltip
func = input.string("EMA", title="indicator name", tooltip="select the name of the indicator function to be used", options=["EMA", "SMA", "RMA", "WMA"])

// input.int: defval, title, options, tooltip
// param1 = input.int(10, title="period parameter")
fastPeriod = input.int(10, title="fastPeriod parameter", options=[5, 10, 20])
slowPeriod = input.int(20, title="slowPeriod parameter", options=[20, 25, 30])

data = input(close, title="data", tooltip="select the closing price, opening price, highest price...")
fastColor = color.red
slowColor = color.red

[fast, slow] = switch func
    "EMA" =>
        fastLine = ta.ema(data, fastPeriod)
        slowLine = ta.ema(data, slowPeriod)
        fastColor := color.red
        slowColor := color.red
        [fastLine, slowLine]
    "SMA" =>
        fastLine = ta.sma(data, fastPeriod)
        slowLine = ta.sma(data, slowPeriod)
        fastColor := color.green
        slowColor := color.green
        [fastLine, slowLine]
    "RMA" =>
        fastLine = ta.rma(data, fastPeriod)
        slowLine = ta.rma(data, slowPeriod)
        fastColor := color.blue
        slowColor := color.blue
        [fastLine, slowLine]
    =>
        runtime.error("error")
        
plot(fast, title="fast" + fastPeriod, color=fastColor, overlay=true)
plot(slow, title="slow" + slowPeriod, color=slowColor, overlay=true)

আমরা ইনপুট ফাংশন আগে শিখেছি, এখানে আমরা ইনপুট অনুরূপ দুটি ফাংশন শিখতে অব্যাহতঃinput.string, input.int functions. input.stringএকটি স্ট্রিং ফেরত ব্যবহার করা হয়, এবংinput.intফাংশন একটি পূর্ণসংখ্যা মান ফেরত ব্যবহার করা হয়. উদাহরণে, একটি নতুন ব্যবহার আছেoptionsপ্যারামিটার।optionsপ্যারামিটার অপশনাল মান একটি অ্যারে পাস করা যেতে পারে, যেমনoptions=["EMA", "SMA", "RMA", "WMA"]এবংoptions=[5, 10, 20]উদাহরণে (নোট করুন যে একটি স্ট্রিং টাইপ, অন্যটি একটি সংখ্যাসূচক টাইপ) । এইভাবে, কৌশল ইন্টারফেসের কন্ট্রোলগুলিকে নির্দিষ্ট মানগুলি ইনপুট করার প্রয়োজন নেই, তবে কন্ট্রোলগুলি বিকল্প প্যারামিটারে প্রদত্ত এই বিকল্পগুলি নির্বাচন করতে ড্রপ-ডাউন বাক্স হয়ে যায়।

ভেরিয়েবল func এর মান একটি স্ট্রিং, এবং ভেরিয়েবল func সুইচের জন্য এক্সপ্রেশন হিসাবে ব্যবহৃত হয় (যা একটি ভেরিয়েবল, ফাংশন কল, বা এক্সপ্রেশন হতে পারে) সুইচের কোন শাখাটি কার্যকর করা হয় তা নির্ধারণ করতে। যদি ভেরিয়েবল func সুইচের যে কোনও শাখার এক্সপ্রেশনটির সাথে মেলে না (যেমন, সমান) তবে ডিফল্ট শাখা কোড ব্লকটি কার্যকর হবে এবংruntime.error("error")ফাংশনটি কার্যকর করা হবে, যার ফলে কৌশলটি একটি ব্যতিক্রম ছুঁড়ে ফেলবে এবং থামবে।

উপরে আমাদের পরীক্ষার কোডে, সুইচ এর ডিফল্ট শাখা কোড ব্লকের রানটাইম.ত্রুটি এর শেষ লাইনের পরে, আমরা রিটার্ন মানের সাথে সামঞ্জস্যপূর্ণ হতে [na, na] এর মতো কোড যুক্ত করি নি। এই সমস্যাটি ট্রেডিং ভিউতে বিবেচনা করা দরকার। যদি টাইপটি অসঙ্গতিপূর্ণ হয় তবে একটি ত্রুটি রিপোর্ট করা হবে। তবে এফএমজেডে, টাইপটি কঠোরভাবে প্রয়োজনীয় না হওয়ায়, এই সামঞ্জস্যের কোডটি বাদ দেওয়া যেতে পারে। অতএব, এফএমজেডে যদি এবং সুইচ শাখাগুলির রিটার্ন মানের টাইপ সামঞ্জস্যতা বিবেচনা করার দরকার নেই।

strategy("test", overlay=true)
x = if close > open
    close
else
    "open"
plotchar(true, title="x", char=str.tostring(x), location=location.abovebar, color=color.red)

FMZ এ কোন ত্রুটি রিপোর্ট করা হবে না, কিন্তু ট্রেডিং ভিউতে একটি ত্রুটি রিপোর্ট করা হবে। কারণ if শাখার দ্বারা ফেরত দেওয়া টাইপ অসঙ্গতিপূর্ণ।

  1. switchকোন এক্সপ্রেশন ছাড়া

এরপরে, আসুন অন্য একটি উপায় ব্যবহার করা যাকswitchমানে, মুখের কোনো অভিব্যক্তি ছাড়াই।

up = close > open     // up = close < open 
down = close < open 
var upOfCount = 0 
var downOfCount = 0 

msgColor = switch
    up  => 
        upOfCount += 1 
        color.green 
    down => 
        downOfCount += 1
        color.red

plotchar(up, title="up", char=str.tostring(upOfCount), location=location.abovebar, color=msgColor, overlay=true)
plotchar(down, title="down", char=str.tostring(downOfCount), location=location.belowbar, color=msgColor, overlay=true)

যেমনটি আমরা পরীক্ষার কোড উদাহরণ থেকে দেখতে পাচ্ছি, সুইচ স্থানীয় কোড ব্লকের এক্সিকিউশনের সাথে মিলবে যা শাখা শর্তে সত্য। সাধারণভাবে, সুইচ স্ট্র্যাটেক্সের পরে শাখা শর্তগুলি অবশ্যই পরস্পরকে বহির্ভূত করতে হবে। অর্থাৎ, উদাহরণে উপরে এবং নীচে একই সময়ে সত্য হতে পারে না। কারণ সুইচ কেবলমাত্র একটি শাখার স্থানীয় কোড ব্লকটি কার্যকর করতে পারে, যদি আপনি আগ্রহী হন তবে আপনি কোডে এই লাইনটি প্রতিস্থাপন করতে পারেনঃup = close > open // up = close < openআপনি দেখতে পাবেন যে সুইচ শাখা শুধুমাত্র প্রথম শাখা চালাতে পারে। উপরন্তু, এটি সুইচ শাখায় যতটা সম্ভব ফাংশন কল লিখতে না মনোযোগ দিতে প্রয়োজন, ফাংশনটি প্রতিটি BAR এ কল করা যাবে না কিছু ডেটা গণনা সমস্যা হতে পারে (যদি না উদাহরণ হিসাবে "switchএক্সপ্রেশন" এর সাথে, এক্সিকিউশন শাখাটি নির্ধারক এবং কৌশল অপারেশনের সময় পরিবর্তন করা হবে না) ।

লুপ কাঠামো

বিবৃতি জন্য

return value = for count = start count to final count by step length
    statement                                            // Note: There can be break and continue in the statement
    statement                                            // Note: The last statement is the return value

ফর স্ট্রেশনটি ব্যবহার করা খুব সহজ, ফর লুপটি অবশেষে একটি মান (বা একাধিক মান, [a, b, c] আকারে) ফেরত দিতে পারে। উপরের ছদ্ম কোডের return value অবস্থানে নির্ধারিত ভেরিয়েবলের মতো। ফর স্ট্রেশনটির পরে একটি count ভেরিয়েবল রয়েছে যা লুপের সংখ্যা নিয়ন্ত্রণ করতে, অন্যান্য মানগুলি উল্লেখ করতে ইত্যাদি ব্যবহৃত হয়। লুপ শুরু হওয়ার আগে count ভেরিয়েবলকে প্রারম্ভিক গণনা বরাদ্দ করা হয়, তারপরে step length সেটিং অনুসারে বৃদ্ধি পায় এবং count ভেরিয়েবল final count এর চেয়ে বড় হলে লুপটি বন্ধ হয়ে যায়।

দ্যbreakফর লুপে ব্যবহৃত কীওয়ার্ডঃ লুপটি বন্ধ হয়ে যায় যখনbreakবিবৃতি কার্যকর করা হয়. দ্যcontinueফর লুপে ব্যবহৃত কীওয়ার্ডঃ যখনcontinueস্ট্রেশনটি চালানো হলে, লুপ কোডটি উপেক্ষা করবেcontinueএবং লুপের পরবর্তী রাউন্ডটি সরাসরি চালান। for স্ট্রাকশনটি লুপের শেষ এক্সিকিউশন থেকে রিটার্ন মানটি ফেরত দেয়। এবং যদি কোনও কোড চালানো না হয় তবে এটি null ফেরত দেয়।

তারপর আমরা একটি সহজ উদাহরণ দিয়ে দেখাবোঃ

ret = for i = 0 to 10       // We can increase the keyword by to modify the step length, FMZ does not support reverse loops such as i = 10 to 0 for now
    // We can add condition settings, use continue to skip, use break to jump out
    runtime.log("i:", i)
    i                       // If this line is not written, it will return null because there is no variable to return
    
runtime.log("ret:", ret)
runtime.error("stop")

জন্য... বিবৃতিতে

দ্যfor ... inবিবৃতি দুটি ফর্ম আছে, আমরা নিম্নলিখিত ছদ্ম কোডে তাদের চিত্রিত করব।

return value = for array element in array 
    statement                        // Note: There can be break and continue in the statement
    statement                        // Note: The last statement is the return value
Return value = for [index variable, array element corresponding to index variable] in array
    statement                        // Note: There can be break and continue in the statement
    statement                        // Note: The last statement is the return value 

আমরা দেখতে পাচ্ছি যে দুটি ফর্মের মধ্যে প্রধান পার্থক্য হ'ল for কীওয়ার্ডের পরে থাকা সামগ্রী, একটি হল একটি ভেরিয়েবলকে একটি ভেরিয়েবল হিসাবে ব্যবহার করা যা অ্যারের উপাদানগুলিকে বোঝায়, অন্যটি হ'ল সূচক ভেরিয়েবলগুলি, রেফারেন্স হিসাবে অ্যারে উপাদান ভেরিয়েবলগুলির টুপলগুলি ধারণকারী একটি কাঠামো ব্যবহার করা। অন্যান্য রিটার্ন মানের নিয়মগুলির জন্য, যেমন বিরতি, চালিয়ে যাওয়া ইত্যাদি ব্যবহার করা, লুপগুলির জন্য সামঞ্জস্যপূর্ণ। আমরা একটি সহজ উদাহরণ দিয়ে ব্যবহারটিও চিত্রিত করি।

testArray = array.from(10, 20, 30, 40, 50, 60, 70, 80, 90, 100)
for ele in testArray            // Modify it to the form of [i, ele]: for [i, ele] in testArray, runtime.log("ele:", ele, ", i:", i)
    runtime.log("ele:", ele)

runtime.error("stop")

যখন এটি সূচক ব্যবহার করতে হবে, ব্যাকরণ ব্যবহার করুনfor [i, ele] in testArray.

লুপের জন্য প্রয়োগ

আমরা পাইন ভাষায় প্রদত্ত বিল্ট-ইন ফাংশনগুলি ব্যবহার করতে পারি লুপ লজিক গণনার কিছু সম্পূর্ণ করতে, হয় সরাসরি লুপ কাঠামো ব্যবহার করে লিখিত বা বিল্ট-ইন ফাংশন ব্যবহার করে প্রক্রিয়াজাত। আসুন দুটি উদাহরণ নিইঃ

  1. গড় মান গণনা করুন

যখন একটি লুপ কাঠামো দিয়ে ডিজাইন করা হয়ঃ

length = 5
var a = array.new(length)
array.push(a, close)

if array.size(a) >= length
	array.remove(a, 0)
	
sum = 0 	
for ele in a
    sum += ele 

avg = sum / length
plot(avg, title="avg", overlay=true)

উদাহরণটি যোগফল গণনা করতে এবং তারপরে গড় মান গণনা করতে একটি ফর লুপ ব্যবহার করে।

অন্তর্নির্মিত ফাংশন ব্যবহার করে সরাসরি চলমান গড় গণনা করুনঃ

plot(ta.sma(close, length), title="ta.sma", overlay=true)

অন্তর্নির্মিত ফাংশন ব্যবহার করুনta.smaএটি স্পষ্টতই চলমান গড় সূচক গণনা করার জন্য অন্তর্নির্মিত ফাংশনটি ব্যবহার করা সহজ। চার্টে তুলনা করে, এটি দেখা যায় যে গণনা করা ফলাফলগুলি ঠিক একই।

  1. সংক্ষিপ্তসার

আমরা এখনও উপরের উদাহরণটি ব্যবহার করি।

যখন একটি লুপ কাঠামো দিয়ে ডিজাইন করা হয়ঃ

length = 5
var a = array.new(length)
array.push(a, close)

if array.size(a) >= length
	array.remove(a, 0)
	
sum = 0 	
for ele in a
    sum += ele 

avg = sum / length
plot(avg, title="avg", overlay=true)
plot(ta.sma(close, length), title="ta.sma", overlay=true)

একটি অ্যারেতে সমস্ত উপাদানের যোগফল গণনা করার জন্য, আমরা এটি প্রক্রিয়া করার জন্য একটি লুপ ব্যবহার করতে পারেন, অথবা বিল্ট ইন ফাংশন ব্যবহারarray.sumগণনা করতে। অন্তর্নির্মিত ফাংশন ব্যবহার করে সরাসরি যোগফল গণনা করুনঃ

length = 5
var a = array.new(length)
array.push(a, close)

if array.size(a) >= length
	array.remove(a, 0)
	
plot(array.sum(a) / length, title="avg", overlay=true)
plot(ta.sma(close, length), title="ta.sma", overlay=true)

আমরা দেখতে পাচ্ছি যে গণনা করা তথ্যগুলি চার্ট ব্যবহার করে প্রদর্শিত তথ্যের সাথে ঠিক একই।

তাহলে কেন লুপ ডিজাইন করবেন যখন আমরা অন্তর্নির্মিত ফাংশন দিয়ে সব করতে পারি? লুপের ব্যবহার মূলত এই তিনটি পয়েন্টের প্রয়োগের উপর ভিত্তি করেঃ

  1. কিছু অপারেশন এবং অ্যারে জন্য গণনার জন্য।
  2. ইতিহাস পর্যালোচনা করার জন্য, উদাহরণস্বরূপ, বর্তমান BAR এর সর্বোচ্চ পয়েন্টের চেয়ে কতগুলি অতীতের সর্বোচ্চ পয়েন্ট উচ্চতর তা খুঁজে বের করতে। যেহেতু বর্তমান BAR এর সর্বোচ্চ পয়েন্টটি কেবলমাত্র সেই BAR এ জানা যায় যেখানে স্ক্রিপ্টটি চালিত হচ্ছে, অতীতের BARগুলি ফিরে আসার এবং বিশ্লেষণ করার জন্য একটি লুপ প্রয়োজন।
  3. যখন পাইন ভাষা অন্তর্নির্মিত ফাংশনগুলি অতীতের BARs এর জন্য গণনা সম্পূর্ণ করতে পারে না।

statemnet এর সময়

দ্যwhilewhile স্ট্রাকচারের বিচার শর্তটি মিথ্যা না হওয়া পর্যন্ত লুপ সেকশনে কোডটি চালিয়ে যায়।

return value = while judgment condition
    statement                    // Note: There can be break and continue in the statement
    statement                    // Note: The last statement is the return value

while এর অন্যান্য নিয়মগুলি for লুপের অনুরূপ। লুপের দেহের স্থানীয় কোড ব্লকের শেষ লাইনটি হল রিটার্ন মান, যা একাধিক মান ফেরত দিতে পারে। loop condition সত্য হলে লুপটি কার্যকর করুন এবং শর্তটি মিথ্যা হলে লুপটি বন্ধ করুন। বিরতি এবং চালিয়ে যাওয়ার বিবৃতিগুলিও লুপের দেহে ব্যবহার করা যেতে পারে।

আমরা এখনও প্রদর্শনের জন্য চলমান গড় গণনার উদাহরণ ব্যবহার করবঃ

length = 10

sma(data, length) => 
    i = 0 
    sum = 0 
    while i < 10 
        sum += data[i]
        i += 1
        sum / length

plot(sma(close, length), title="sma", overlay=true)
plot(ta.sma(close, length), title="ta.sma", overlay=true)

আমরা দেখতে পাচ্ছি যে while loop ব্যবহার করাও খুবই সহজ, এবং কিছু গণনার লজিক ডিজাইন করাও সম্ভব যা অন্তর্নির্মিত ফাংশনগুলির দ্বারা প্রতিস্থাপিত হতে পারে না, যেমন ফ্যাক্টরিয়াল গণনাঃ

counter = 5
fact = 1

ret = while counter > 0
    fact := fact * counter
    counter := counter - 1
    fact

plot(ret, title="ret")  // ret = 5 * 4 * 3 * 2 * 1

অ্যারে

পাইন ভাষায় অ্যারেগুলির সংজ্ঞা অন্যান্য প্রোগ্রামিং ভাষার মতোই। পাইন অ্যারেগুলি এক মাত্রিক অ্যারে। সাধারণত এটি ধারাবাহিক ধারাবাহিক ডেটা সঞ্চয় করতে ব্যবহৃত হয়। অ্যারেতে সঞ্চিত একক ডেটাকে অ্যারেটির উপাদান বলা হয় এবং এই উপাদানগুলির ধরণগুলি হতে পারেঃ পূর্ণসংখ্যা, ভাসমান বিন্দু, স্ট্রিং, রঙের মান, বুলিয়ান মান। এফএমজেডের পাইন ভাষাটি ধরণের বিষয়ে খুব কঠোর নয় এবং এটি একই সাথে অ্যারেতে স্ট্রিং এবং সংখ্যাগুলিও সঞ্চয় করতে পারে। যেহেতু অ্যারেটির অন্তর্নিহিত কাঠামোটিও একটি সিরিয়াল কাঠামো, যদি historical operator ব্যবহার করা হয় তবে পূর্ববর্তী BAR এ অ্যারেটির অবস্থা উল্লেখ করতে। সুতরাং historical operator ব্যবহারের পরিবর্তে[]অ্যারেতে একটি উপাদান উল্লেখ করার জন্য, আমরা ফাংশন ব্যবহার করতে হবেarray.get()এবংarray.set(). অ্যারেতে উপাদানগুলির সূচক ক্রম হল যে অ্যারের প্রথম উপাদানের সূচক 0 এবং পরবর্তী উপাদানের সূচক 1 দ্বারা বৃদ্ধি করা হয়।

আমরা এটিকে একটি সহজ কোড দিয়ে চিত্রিত করি:

var a = array.from(0)
if bar_index == 0 
    runtime.log("current value a on BAR:", a, ", a on the last BAR, i.e. the value of a[1]:", a[1])
else if bar_index == 1 
    array.push(a, bar_index)
    runtime.log("current value a on BAR:", a, ", a on the last BAR, i.e. the value of a[1]:", a[1])
else if bar_index == 2
    array.push(a, bar_index)
    runtime.log("current value a on BAR:", a, ", a on the last BAR, i.e. the value of a[1]:", a[1], ", a on the last second BAR, i.e. the value of a[2]:", a[2])
else if bar_index == 3 
    array.push(a, bar_index)
    runtime.log("current value a on BAR:", a, ", a on the last BAR, i.e. the value of a[1]:", a[1], ", a on the last second BAR, i.e. the value of a[2]:", a[2], ", a on the last third BAR, i.e. the value of a[3]:", a[3])
else if bar_index == 4 
    // Obtain elements by index using array.get, modify elements by index using array.set
    runtime.log("Before array modification:", array.get(a, 0), array.get(a, 1), array.get(a, 2), array.get(a, 3))
    array.set(a, 1, 999)
    runtime.log("After array modification:", array.get(a, 0), array.get(a, 1), array.get(a, 2), array.get(a, 3))

একটি অ্যারে ঘোষণা করুন

ব্যবহারarray<int> a, float[] bএকটি অ্যারে ঘোষণা করতে বা কেবল একটি ভেরিয়েবল ঘোষণা করতে যা একটি অ্যারে বরাদ্দ করা যেতে পারে, উদাহরণস্বরূপঃ

array<int> a = array.new(3, bar_index)
float[] b = array.new(3, close)
c = array.from("hello", "fmz", "!")
runtime.log("a:", a)
runtime.log("b:", b)
runtime.log("c:", c)
runtime.error("stop")

অ্যারে ভেরিয়েবলগুলি ব্যবহার করে শুরু করা হয়array.newএবংarray.fromফাংশন. এছাড়াও অনেক ধরনের সাথে সম্পর্কিত ফাংশন অনুরূপ আছেarray.newপাইন ভাষায়:array.new_int(), array.new_bool(), array.new_color(), array.new_string()ইত্যাদি।

var কীওয়ার্ডটি অ্যারে ঘোষণার মোডের সাথেও কাজ করে। var কীওয়ার্ড দিয়ে ঘোষিত অ্যারেগুলি কেবলমাত্র প্রথম BAR এ শুরু হয়। আসুন একটি উদাহরণ দিয়ে পর্যবেক্ষণ করিঃ

var a = array.from(0)
b = array.from(0)

if bar_index == 1
    array.push(a, bar_index)
    array.push(b, bar_index)
else if bar_index == 2 
    array.push(a, bar_index)
    array.push(b, bar_index)
else if barstate.islast
    runtime.log("a:", a)
    runtime.log("b:", b)
    runtime.error("stop")

এটি দেখা যায় যে অ্যারে a এর পরিবর্তনগুলি ক্রমাগত নির্ধারিত হয়েছে এবং পুনরায় সেট করা হয়নি। অ্যারে b প্রতিটি BAR এ শুরু হয়। অবশেষে, যখনbarstate.islastযদি সত্য হয়, তাহলেও মাত্র একটি উপাদান আছে যার মান ০।

একটি অ্যারেতে উপাদানগুলি পড়ুন এবং লিখুন

অ্যারেতে নির্দিষ্ট সূচক অবস্থানে উপাদানটি পেতে array.get ব্যবহার করুন এবং অ্যারেতে নির্দিষ্ট সূচক অবস্থানে উপাদানটি সংশোধন করতে array.set ব্যবহার করুন।

array.get এর প্রথম প্যারামিটার হল প্রক্রিয়া করা প্যারামিটার, এবং দ্বিতীয় প্যারামিটার হল নির্দিষ্ট সূচক। array.set এর প্রথম প্যারামিটার হল প্রক্রিয়া করা প্যারামিটার, দ্বিতীয় প্যারামিটার হল নির্দিষ্ট সূচক এবং তৃতীয় প্যারামিটার হল লিখিত উপাদান।

আমরা নিম্নলিখিত সহজ উদাহরণটি ব্যবহার করিঃ

lookbackInput = input.int(100)
FILL_COLOR = color.green

var fillColors = array.new(5)
if barstate.isfirst
    array.set(fillColors, 0, color.new(FILL_COLOR, 70))
    array.set(fillColors, 1, color.new(FILL_COLOR, 75))
    array.set(fillColors, 2, color.new(FILL_COLOR, 80))
    array.set(fillColors, 3, color.new(FILL_COLOR, 85))
    array.set(fillColors, 4, color.new(FILL_COLOR, 90))

lastHiBar = - ta.highestbars(high, lookbackInput)
fillNo = math.min(lastHiBar / (lookbackInput / 5), 4)

bgcolor(array.get(fillColors, int(fillNo)), overlay=true)
plot(lastHiBar, title="lastHiBar")
plot(fillNo, title="fillNo")

উদাহরণটি বেস রঙ সবুজ শুরু করে, রঙগুলি সংরক্ষণ করতে একটি অ্যারে ঘোষণা করে এবং শুরু করে এবং তারপরে রঙগুলিতে বিভিন্ন স্বচ্ছতার মান নির্ধারণ করে (পরিচয় ব্যবহার করে)color.newরঙের স্তরটি বর্তমান BAR এর সর্বোচ্চ মান থেকে 100 টি লুকব্যাক পিরিয়ডে সর্বোচ্চ মান থেকে দূরত্ব গণনা করে গণনা করা হয়। শেষ 100 লুকব্যাক চক্রগুলিতে সর্বোচ্চ মানের কাছাকাছি দূরত্ব, র্যাঙ্কটি আরও বেশি এবং সংশ্লিষ্ট রঙের মানটি আরও গা dark় (নিম্ন স্বচ্ছতা) । অনেক অনুরূপ কৌশল N লুকব্যাক পিরিয়ডের মধ্যে বর্তমান মূল্যের স্তর উপস্থাপনের জন্য এই পদ্ধতিটি ব্যবহার করে।

অ্যারে উপাদানগুলির মাধ্যমে পুনরাবৃত্তি করুন

কিভাবে একটি অ্যারের মাধ্যমে পুনরাবৃত্তি করা যায়, আমরা for/for in/while স্ট্রেশন ব্যবহার করতে পারি যা আমরা আগে শিখেছি।

a = array.from(1, 2, 3, 4, 5, 6)

for i = 0 to (array.size(a) == 0 ? na : array.size(a) - 1)
    array.set(a, i, i)
    
runtime.log(a)
runtime.error("stop")
a = array.from(1, 2, 3, 4, 5, 6)

i = 0
while i < array.size(a)
    array.set(a, i, i)
    i += 1

runtime.log(a)
runtime.error("stop")
a = array.from(1, 2, 3, 4, 5, 6)

for [i, ele] in a 
    array.set(a, i, i)

runtime.log(a)
runtime.error("stop")

এই তিনটি ট্রাভার্সাল পদ্ধতির একই কার্যকর ফলাফল রয়েছে।

অ্যারেগুলি স্ক্রিপ্টের গ্লোবাল স্কোপে, অথবা ফাংশন বা if শাখার স্থানীয় স্কোপে ঘোষণা করা যেতে পারে।

ঐতিহাসিক তথ্যের উল্লেখ

অ্যারেতে উপাদানের ব্যবহারের জন্য, নিম্নলিখিত উপায়গুলি সমতুল্য। আমরা নিম্নলিখিত উদাহরণ দ্বারা দেখতে পারি যে চার্টটিতে দুটি সেট লাইন আঁকা হয়, প্রতিটি সেটে দুটি, এবং প্রতিটি সেটে দুটি লাইনের ঠিক একই মান রয়েছে।

a = array.new_float(1)
array.set(a, 0, close)
closeA1 = array.get(a, 0)[1]
closeB1 = close[1]
plot(closeA1, "closeA1", color.red, 6)
plot(closeB1, "closeB1", color.black, 2)

ma1 = ta.sma(array.get(a, 0), 20)
ma2 = ta.sma(close, 20)
plot(ma1, "ma1", color.aqua, 6)
plot(ma2, "ma2", color.black, 2)

অ্যারে যোগ এবং মুছে ফেলার জন্য ফাংশন

  1. অ্যারে যোগ করার অপারেশন সম্পর্কিত ফাংশনঃ

array.unshift(), array.insert(), array.push().

  1. অ্যারে মুছে ফেলার সাথে সম্পর্কিত ফাংশনঃ

array.remove(), array.shift(), array.pop(), array.clear().

আমরা এই অ্যারে যোগ এবং অপসারণ অপারেশন ফাংশন পরীক্ষা করার জন্য নিম্নলিখিত উদাহরণ ব্যবহার।

a = array.from("A", "B", "C")
ret = array.unshift(a, "X")
runtime.log("array a:", a, ", ret:", ret)

ret := array.insert(a, 1, "Y")
runtime.log("array a:", a, ", ret:", ret)

ret := array.push(a, "D")
runtime.log("array a:", a, ", ret:", ret)

ret := array.remove(a, 2)
runtime.log("array a:", a, ", ret:", ret)

ret := array.shift(a)
runtime.log("array a:", a, ", ret:", ret)

ret := array.pop(a)
runtime.log("array a:", a, ", ret:", ret)

ret := array.clear(a)
runtime.log("array a:", a, ", ret:", ret)

runtime.error("stop")

সংযোজন, অপসারণের প্রয়োগঃ অ্যারেগুলিকে সারি হিসাবে

আমরা অ্যারে এবং অ্যারে যোগ এবং মুছে ফেলার কিছু ফাংশন ব্যবহার করে একটি queue ডেটা কাঠামো তৈরি করতে পারি। টিকের দামের চলমান গড় গণনা করতে ক্যু ব্যবহার করা যেতে পারে। কেউ জিজ্ঞাসা করতে পারে, কেন আমাদের একটি ক্যু কাঠামো তৈরি করা উচিত? আমরা কি আগে গড় গণনা করতে অ্যারে ব্যবহার করিনি?

একটি ক্যু একটি কাঠামো যা প্রায়শই প্রোগ্রামিংয়ের ক্ষেত্রে ব্যবহৃত হয়, একটি ক্যু বৈশিষ্ট্যগুলি হ'লঃ

যে উপাদানটি প্রথম সারিতে প্রবেশ করে, সে প্রথম সারিতে চলে যায়।

এইভাবে, এটি নিশ্চিত করে যে সারিটির ডেটা সর্বশেষতম ডেটা এবং সারিটির দৈর্ঘ্য অনির্দিষ্টকালের জন্য প্রসারিত হবে না।

নিম্নলিখিত উদাহরণে, আমরা প্রতিটি টিকের মূল্য রেকর্ড করার জন্য একটি সারি কাঠামো ব্যবহার করি, টিকের স্তরে গতিশীল গড় মূল্য গণনা করি এবং তারপরে এটি 1 মিনিটের কে-লাইন স্তরে চলমান গড়ের সাথে তুলনা করি।

strategy("test", overlay=true)

varip a = array.new_float(0)
var length = 10

if not barstate.ishistory
    array.push(a, close)

    if array.size(a) > length
        array.shift(a)

sum = 0.0
for [index, ele] in a 
    sum += ele

avgPrice = array.size(a) == length ? sum / length : na

plot(avgPrice, title="avgPrice")
plot(ta.sma(close, length), title="ta.sma")

মনে রাখবেন যে যখন অ্যারে a ঘোষণা করা হয়, তখন আমরা ঘোষণা মোড নির্দিষ্ট করি এবং কীওয়ার্ড ব্যবহার করিvariant. এই ভাবে, প্রতিটি মূল্য পরিবর্তন অ্যারে একটি রেকর্ড করা হবে.

সাধারণত ব্যবহৃত অ্যারে গণনা এবং অপারেশন ফাংশন

সংশ্লিষ্ট ফাংশন গণনা করুনঃ

array.avg()একটি অ্যারেতে সমস্ত উপাদানের গড় মান গণনা করে,array.min()একটি অ্যারেতে ক্ষুদ্রতম উপাদান গণনা করে,array.max()একটি অ্যারেতে ক্ষুদ্রতম উপাদান গণনা করে,array.stdev()একটি অ্যারেতে সমস্ত উপাদানের স্ট্যান্ডার্ড ডিভিয়েশন গণনা করে,array.sum()একটি অ্যারেতে সমস্ত উপাদানের স্ট্যান্ডার্ড বিচ্যুতি গণনা করে।

অপারেশন সম্পর্কিত ফাংশনঃarray.concat()দুটি অ্যারে একত্রিত বা সংযুক্ত করতে।array.copy()অ্যারে কপি করতে.array.jointo একটি অ্যারের সকল উপাদানকে একটি স্ট্রিংয়ে সংযুক্ত করে।array.sort()ক্রমবর্ধমান বা হ্রাসপ্রাপ্ত আদেশ দ্বারা সাজানোর জন্য।array.reverse()অ্যারেটি বিপরীত করার জন্য।array.slice()অ্যারেটি কেটে ফেলতে।array.includes()উপাদান বিচার করতে.array.indexof()যদি মানটি পাওয়া না যায়, -1 ফেরত দেওয়া হবে।array.lastindexof()মানের সর্বশেষ ঘটনা খুঁজে পেতে.

অ্যারে গণনার সাথে সম্পর্কিত ফাংশনের পরীক্ষার উদাহরণঃ

a = array.from(3, 2, 1, 4, 5, 6, 7, 8, 9)

runtime.log("Arithmetic average of the array a:", array.avg(a))
runtime.log("The minimum element in the array a:", array.min(a))
runtime.log("The maximum element in the array a:", array.max(a))
runtime.log("Standard deviation in array a:", array.stdev(a))
runtime.log("Sum of all elements of the array a:", array.sum(a))
runtime.error("stop")

এগুলি সাধারণত ব্যবহৃত অ্যারে গণনা ফাংশন।

অপারেশন সম্পর্কিত ফাংশনের উদাহরণঃ

a = array.from(1, 2, 3, 4, 5, 6)
b = array.from(11, 2, 13, 4, 15, 6)

runtime.log("array a: ", a, ", array b: ", b)
runtime.log("array a, array b is concatenated with:", array.concat(a, b))
c = array.copy(b)

runtime.log("Copy an array b and assign it to the variable c, variable c:", c)

runtime.log("use array.join to process the array c, add the symbol + to the middle of each element, concatenating all elements results in a string:", array.join(c, "+"))
runtime.log("Sort the array b, in order from smallest to largest, using the parameter order.ascending:", array.sort(b, order.ascending))     // array.sort function modifies the original array
runtime.log("Sort the array b, in order from largest to smallest, using the parameter order.descending:", array.sort(b, order.descending))   // array.sort function modifies the original array

runtime.log("array a:", a, ", array b:", b)
array.reverse(a)   // This function modifies the original array
runtime.log("reverse the order of all elements in the array a, after reversing, the array a is:", a)    

runtime.log("Intercept array a, index 0~index 3, and follow the rule of left-closed and right-open interval:", array.slice(a, 0, 3))
runtime.log("Search for element 11 in array b:", array.includes(b, 11))
runtime.log("Search for element 100 in array a:", array.includes(a, 100))
runtime.log("Connect array a and array b, and search the index position of the first occurrence of element 2:", array.indexof(array.concat(a, b), 2), " , observe array.concat(a, b):", array.concat(a, b))
runtime.log("Connect array a and array b, and search the index position of the last occurrence of element 6:", array.lastindexof(array.concat(a, b), 6), " , observe array.concat(a, b):", array.concat(a, b))

runtime.error("stop")

কার্যাবলী

কাস্টম ফাংশন

পাইন ভাষা কাস্টম ফাংশন দিয়ে ডিজাইন করা যেতে পারে। সাধারণভাবে, পাইন ভাষায় কাস্টম ফাংশনগুলিতে নিম্নলিখিত নিয়মগুলি প্রয়োগ করা হয়ঃ

  1. সমস্ত ফাংশন স্ক্রিপ্টের গ্লোবাল স্কোপে সংজ্ঞায়িত করা হয়। একটি ফাংশন অন্য ফাংশনের মধ্যে ঘোষিত হতে পারে না।
  2. ফাংশনগুলিকে তাদের নিজস্ব কোড (পুনরাবৃত্তি) তে নিজেদেরকে কল করার অনুমতি নেই।
  3. নীতিগতভাবে, সমস্ত পাইন ভাষার অন্তর্নির্মিত অঙ্কন ফাংশন (barcolor(), fill(), hline(), plot(), plotbar(), plotcandle()) কাস্টম ফাংশনে কল করা যাবে না।
  4. ফাংশনগুলি একক লাইন বা একাধিক লাইন হিসাবে লেখা যেতে পারে। শেষ বিবৃতির রিটার্ন মানটি বর্তমান ফাংশনের রিটার্ন মান, যা টিপল আকারে ফিরে আসতে পারে।

আমরা আমাদের পূর্ববর্তী টিউটোরিয়ালগুলিতে কাস্টম ফাংশনগুলি অনেকবার ব্যবহার করেছি, যেমন একটি একক লাইন হিসাবে ডিজাইন করা হয়েছেঃ

barIsUp() => close > open

ফাংশনটি ফেরত দেওয়ার সময় বর্তমান BAR একটি ধনাত্মক রেখা কিনা।

কাস্টম ফাংশন একাধিক লাইন হতে ডিজাইন করা হয়েছেঃ

sma(data, length) => 
    i = 0 
    sum = 0 
    while i < 10 
        sum += data[i]
        i += 1
        sum / length

plot(sma(close, length), title="sma", overlay=true)
plot(ta.sma(close, length), title="ta.sma", overlay=true)

আমরা একটি কাস্টম ফাংশন ব্যবহার করি SMA গড় গণনার একটি ফাংশন উপলব্ধি করতে।

এছাড়াও, কাস্টম ফাংশনের দুটি উদাহরণ যা আমরা ফেরত দিতে পারিঃ

twoEMA(data, fastPeriod, slowPeriod) =>
    fast = ta.ema(data, fastPeriod)
    slow = ta.ema(data, slowPeriod)
    [fast, slow]

[ema10, ema20] = twoEMA(close, 10, 20)
plot(ema10, title="ema10", overlay=true)
plot(ema20, title="ema20", overlay=true)

একটি ফাংশন দ্রুত লাইন, ধীর লাইন এবং দুটি ইএমএ গড় গণনা করতে পারে।

বিল্ট ইন ফাংশন

অন্তর্নির্মিত ফাংশনগুলি সহজেইFMZ PINE স্ক্রিপ্ট নথি.

পাইন ভাষায় অন্তর্নির্মিত ফাংশনগুলির শ্রেণীবিভাগঃ

  1. স্ট্রিং প্রসেসিং ফাংশনstr. series.
  2. রঙ মান প্রক্রিয়াকরণ ফাংশনcolor. series.
  3. প্যারামিটার ইনপুট ফাংশনinput. series.
  4. সূচক গণনা ফাংশনta. series.
  5. অঙ্কন ফাংশনplot. series.
  6. অ্যারে হ্যান্ডলিং ফাংশনarray. series.
  7. ট্রেডিং সম্পর্কিত ফাংশনstrategy. series.
  8. গণিত অপারেশন সম্পর্কিত ফাংশনmath. series.
  9. অন্যান্য ফাংশন (সময় হ্যান্ডলিং, অ-গ্রাফ সিরিজ অঙ্কন ফাংশন,request.সিরিজ ফাংশন, টাইপ হ্যান্ডলিং ফাংশন ইত্যাদি)

ট্রেডিং ফাংশন

দ্যstrategy.ফাংশন সিরিজ ফাংশন যা আমরা প্রায়ই কৌশল নকশা ব্যবহার, এবং এই ফাংশন ঘনিষ্ঠভাবে ট্রেডিং অপারেশন বাস্তবায়ন যখন কৌশল চলমান হয় ঘনিষ্ঠভাবে সম্পর্কিত হয়।


  1. strategy.entry

strategy.entryফাংশন একটি আরো গুরুত্বপূর্ণ ফাংশন যখন আমরা একটি অর্ডার স্থাপন করার জন্য একটি কৌশল লিখতে, ফাংশন জন্য বেশ কয়েকটি গুরুত্বপূর্ণ পরামিতি হয়ঃid, direction, qty, whenইত্যাদি।

পরামিতিঃ

  • id: এটি একটি ট্রেডিং পজিশনের নাম উল্লেখ করার জন্য বোঝা যেতে পারে। এই আইডিটি বাতিল, আদেশ পরিবর্তন এবং অবস্থান বন্ধ করার জন্য উল্লেখ করা যেতে পারে।
  • direction: যদি অর্ডারের দিকটি দীর্ঘ হয় (buy), অন্তর্নির্মিত ভেরিয়েবলটি পাস করুনstrategy.long, এবং যদি আপনি সংক্ষিপ্ত যেতে চান (বিক্রয়), পরিবর্তনশীল পাসstrategy.short.
  • qty: অর্ডার দেওয়ার পরিমাণ নির্দিষ্ট করুন, যদি এই প্যারামিটারটি পাস না করা হয়, তাহলে ডিফল্ট অর্ডার পরিমাণ ব্যবহার করা হবে।
  • when: এক্সিকিউশন শর্ত, আপনি এই প্যারামিটারটি নির্দিষ্ট করতে পারেন এই বর্তমান অর্ডার অপারেশনটি ট্রিগার করা হয় কিনা তা নিয়ন্ত্রণ করতে।
  • limit: অর্ডারের সীমা মূল্য উল্লেখ করুন।
  • stop: স্টপ লস মূল্য।

চুক্তির কার্যকরকরণের নির্দিষ্ট বিবরণstrategy.entryফাংশন প্যারামিটার সেটিংস দ্বারা নিয়ন্ত্রিত হয় যখনstrategyফাংশন বলা হয়, এবং এটি [ পাইন ভাষা ট্রেড-ক্লাস লাইব্রেরি টেমপ্লেট আর্গুমেন্ট](https://www.fmz.com/bbs-topic/9293#template--arguments-of-pine-language-trade-class-library) সেটিং কন্ট্রোল, পাইন ভাষা ট্রেড-ক্লাস লাইব্রেরি টেমপ্লেট আর্গুমেন্ট লেনদেনের আরো বিস্তারিত নিয়ন্ত্রণ, আপনি বিস্তারিত জানার জন্য লিঙ্কযুক্ত ডকুমেন্টেশন পরীক্ষা করতে পারেন।

আমরা মনোযোগ দিচ্ছিpyramiding, default_qty_valueপ্যারামিটারstrategyআমরা পরীক্ষার জন্য নিম্নলিখিত কোড ব্যবহার করিঃ

/*backtest
start: 2022-07-03 00:00:00
end: 2022-07-09 00:00:00
period: 1d
basePeriod: 1h
exchanges: [{"eid":"Binance","currency":"BTC_USDT"}]
*/

strategy(title = "open long example", pyramiding = 3, default_qty_value=0.1, overlay=true)

ema10 = ta.ema(close, 10)

findOrderIdx(idx) =>
    if strategy.opentrades == 0 
        false 
    else 
        ret = false 
        for i = 0 to strategy.opentrades - 1 
            if strategy.opentrades.entry_id(i) == idx
                ret := true 
                break
        ret 
        

if not findOrderIdx("long1")
    strategy.entry("long1", strategy.long)

if not findOrderIdx("long2")
    strategy.entry("long2", strategy.long, 0.2, when = close > ema10)

if not findOrderIdx("long3")
    strategy.entry("long3", strategy.long, 0.2, limit = low[1])
    strategy.entry("long3", strategy.long, 0.3, limit = low[1])

if not findOrderIdx("long4")
    strategy.entry("long4", strategy.long, 0.2)

plot(ema10, title="ema10", color=color.red)

কোডের শুরুতে অংশ/* backtest... */একটি ব্যাকটেস্ট সেটিং, যা ব্যাকটেস্ট সেটিং সময় এবং ডিবাগিংয়ের জন্য সেই সময়ে অন্যান্য তথ্য রেকর্ড করতে ব্যবহৃত হয়, স্টার্টেজি কোড নয়।

কোডেঃstrategy(title = "open long example", pyramiding = 3, default_qty_value=0.1, overlay=true), যখন আমরা নির্দিষ্টpyramidingপ্যারামিটার হিসাবে 3, আমরা একই দিকের ট্রেড সর্বোচ্চ সংখ্যা সেট 3. তাই চারটি একstrategy.entryঅর্ডার অপারেশন উদাহরণে চালানো হয় না. যেহেতু আমরা এছাড়াও নির্দিষ্টdefault_qty_valueপ্যারামিটার 0.1, এইstrategy.entryআইডি সহ অপারেশনlong1এর ডিফল্ট অর্ডার সাইজ ০.১।strategy.entryফাংশন কল যখন আমরা নির্দিষ্টdirectionযেমনstrategy.long, তাই ব্যাকটেস্ট টেস্ট অর্ডার সব ক্রয় আদেশ হয়.

লক্ষ্য করুন যে অর্ডার অপারেশনstrategy.entry("long3", ...একই আইডি-র জন্য কোডে দুইবার কল করা হয়ঃlong3, প্রথমstrategy.entryঅর্ডার অপারেশন পূরণ করা হয় নি, এবং দ্বিতীয় কলstrategy.entryঅন্য ক্ষেত্রে, উদাহরণস্বরূপ, যদি ID long3 দিয়ে প্রথম অর্ডারটি পূরণ করা হয়, তবে ব্যাকটেস্ট পরীক্ষায় প্রদর্শিত তথ্যগুলিও দেখায় যে এই সীমা অর্ডারের জন্য অর্ডার পরিমাণ 0.3 এ পরিবর্তন করা হয়েছিল।strategy.entryআইডি long3 অনুযায়ী অর্ডার স্থাপন করার জন্য ফাংশন, তারপর অর্ডার অবস্থান আইডি long3 উপর জমা হবে।


  1. strategy.close

দ্যstrategy.closeনির্দিষ্ট সনাক্তকরণ আইডি দিয়ে প্রবেশের অবস্থান বন্ধ করতে ফাংশন ব্যবহার করা হয়। প্রধান পরামিতিগুলি হলঃid, when, qty, qty_percent.

পরামিতিঃ

  • id: এন্ট্রি আইডি যা বন্ধ করতে হবে তা হল আইডি যা আমরা যখন একটি এন্ট্রি অর্ডার ফাংশন ব্যবহার করে একটি অবস্থান খোলার সময় নির্দিষ্ট করি, যেমনঃstrategy.entry.
  • when: কার্যকরকরণের শর্তাবলী।
  • qty: বন্ধ পজিশনের সংখ্যা।
  • qty_percent: বন্ধ পজিশনের শতাংশ।

আসুন একটি উদাহরণ দিয়ে এই ফাংশনটির ব্যবহারের বিশদ সম্পর্কে পরিচিত হইঃ দ্য/*backtest ... */কোডের মধ্যে কনফিগারেশন তথ্য রয়েছেFMZ.COMআন্তর্জাতিক ওয়েবসাইট ব্যাকটেস্ট, আপনি এটি মুছে ফেলতে পারেন এবং বাজার, বৈচিত্র্য, সময় পরিসীমা এবং অন্যান্য তথ্য আপনি পরীক্ষা করতে হবে সেট.

/*backtest
start: 2022-07-03 00:00:00
end: 2022-07-09 00:00:00
period: 1d
basePeriod: 1h
exchanges: [{"eid":"Binance","currency":"BTC_USDT"}]
*/

strategy("close Demo", pyramiding=3)

var enableStop = false 
if enableStop
    runtime.error("stop")

strategy.entry("long1", strategy.long, 0.2)
if strategy.opentrades >= 3 
    strategy.close("long1")                   // Multiple entry orders, no qty parameters specified, close all
    // strategy.close()                          // Without specifying the id parameter, the current position will be closed
    // strategy.close("long2")                   // If a non-existent id is specified then nothing is done
    // strategy.close("long1", qty=0.15)         // Specify qty parameters to close a position
    // strategy.close("long1", qty_percent=50)   // qty_percent is set to 50 to close 50% of the positions marked by long1
    // strategy.close("long1", qty_percent=80, when=close<open)  // Specify the parameter when, change it to close>open and it won't trigger
    enableStop := true

পরীক্ষার কৌশলটি long1 এন্ট্রি আইডি সহ পরপর তিনটি দীর্ঘ এন্ট্রি দেখায় এবং তারপরে পরীক্ষার বিভিন্ন পরামিতি ব্যবহার করে।strategy.closeএকটি অবস্থান বন্ধ করার সময় ব্যাকটেস্টের বিভিন্ন ফলাফল সেট করার জন্য ফাংশন। এটি পাওয়া যাবে যেstrategy.closeএই ফাংশনটি মূলত বর্তমান বাজার মূল্যে অবিলম্বে অবস্থান বন্ধ করার জন্য ব্যবহৃত হয়।


  1. strategy.close_all

ফাংশনstrategy.close_allসব বর্তমান অবস্থান বন্ধ করতে ব্যবহৃত হয়, কারণ পাইন ভাষা স্ক্রিপ্ট অবস্থান শুধুমাত্র একটি দিক থাকতে পারে, যে, যদি বর্তমান অবস্থান বিপরীত দিক একটি সংকেত ট্রিগার বর্তমান অবস্থান বন্ধ এবং তারপর সংকেত ট্রিগার অনুযায়ী এটি খুলতে হবে। তাইstrategy.close_allএটি কল করা হলে বর্তমান দিক সব অবস্থানের বন্ধ হবে.strategy.close_allফাংশন হলঃwhen.

পরামিতিঃ

  • when: কার্যকরকরণের শর্তাবলী।

আসুন একটি উদাহরণ ব্যবহার করে পর্যবেক্ষণ করিঃ

/*backtest
start: 2022-07-03 00:00:00
end: 2022-07-09 00:00:00
period: 1d
basePeriod: 1h
exchanges: [{"eid":"Binance","currency":"BTC_USDT"}]
*/

strategy("closeAll Demo")

var enableStop = false 
if enableStop
    runtime.error("stop")

strategy.entry("long", strategy.long, 0.2, when=strategy.position_size==0 and close>open)
strategy.entry("short", strategy.short, 0.3, when=strategy.position_size>0 and close<open)

if strategy.position_size < 0 
    strategy.close_all()
    enableStop := true 

পরীক্ষার কোড একটি অবস্থান নম্বর 0 দিয়ে শুরু হয় (যেমনstrategy.position_size==0সত্য), তাই যখন যখন প্যারামিটার দ্বারা নির্ধারিত শর্ত পূরণ করা হয়, শুধুমাত্রstrategy.entryআইডি long সঙ্গে এন্ট্রি ফাংশন চালানো হয়। একটি দীর্ঘ অবস্থান ধরে রাখার পরে,strategy.position_size০ এর চেয়ে বড়, তাহলে ID short সহ এন্ট্রি ফাংশনটি কার্যকর করা যেতে পারে, যেহেতু বর্তমান লং পজিশনটি ধরে রাখা হয়েছে, এই সময়ে এই শর্টিং বিপরীত সংকেতটি লং পজিশনটি বন্ধ করার এবং তারপরে বিপরীত দিকের শর্ট পজিশনটি খোলার ফলস্বরূপ হবে। তারপর আমরা যদি শর্তে লিখি যে যখনstrategy.position_size < 0, অর্থাৎ শর্ট পজিশন ধরে রাখার সময় বর্তমান হোল্ডিং দিকের সকল পজিশন বন্ধ হয়ে যাবে।enableStop := true. কৌশল কার্যকর করা বন্ধ করে দেয় যাতে লগটি পর্যবেক্ষণ করা যায়।

এটা পাওয়া যাবে যে ফাংশনstrategy.close_allঅর্ডার বন্ধের মূল্য নির্দিষ্ট করার জন্য কোন পরামিতি নেই, এই ফাংশনটি মূলত বর্তমান বাজার মূল্যে অবিলম্বে অবস্থান বন্ধ করতে ব্যবহৃত হয়।


  1. strategy.exit

দ্যstrategy.exitএই ফাংশন ভিন্ন,strategy.closeএবংstrategy.close_allফাংশন অবিলম্বে বর্তমান বাজার মূল্যে একটি অবস্থান বন্ধ।strategy.exitফাংশন প্যারামিটার সেটিংস অনুযায়ী অবস্থান বন্ধ করবে.

পরামিতিঃ

  • id: বর্তমান ক্লোজআউট শর্ত অর্ডারের অর্ডার আইডি।
  • from_entry: বন্ধ করা পজিশনের এন্ট্রি আইডি নির্দিষ্ট করতে ব্যবহৃত হয়।
  • qty: বন্ধ পজিশনের সংখ্যা।
  • qty_percent: বন্ধ পজিশনের শতাংশ, পরিসীমাঃ 0 ~ 100.
  • profit: মুনাফা লক্ষ্যমাত্রা, পয়েন্টে প্রকাশিত।
  • loss: স্টপ লস টার্গেট, পয়েন্টে প্রকাশিত।
  • limit: মুনাফা লক্ষ্যমাত্রা, মূল্য দ্বারা নির্দিষ্ট।
  • stop: স্টপ লস টার্গেট, মূল্য দ্বারা নির্দিষ্ট।
  • when: কার্যকরকরণের শর্তাবলী।

প্যারামিটার ব্যবহার বোঝার জন্য একটি পরীক্ষার কৌশল ব্যবহার করুন।

/*backtest
start: 2022-07-03 00:00:00
end: 2022-07-09 00:00:00
period: 1d
basePeriod: 1h
exchanges: [{"eid":"Binance","currency":"BTC_USDT"}]
args: [["RunMode",1,358374],["ZPrecision",0,358374]]
*/

strategy("strategy.exit Demo", pyramiding=3)

varip isExit = false 

findOrderIdx(idx) =>
    ret = -1 
    if strategy.opentrades == 0 
        ret
    else 
        for i = 0 to strategy.opentrades - 1 
            if strategy.opentrades.entry_id(i) == idx
                ret := i 
                break
        ret

strategy.entry("long1", strategy.long, 0.1, limit=1, when=findOrderIdx("long1") < 0)
strategy.entry("long2", strategy.long, 0.2, when=findOrderIdx("long2") < 0)
strategy.entry("long3", strategy.long, 0.3, when=findOrderIdx("long3") < 0)

if not isExit and strategy.opentrades > 0
    // strategy.exit("exitAll")          // If only one id parameter is specified, the exit order is invalid, and the parameters profit, limit, loss, stop and other exit conditions also need to be set at least one, otherwise it is also invalid
    strategy.exit("exit1", "long1", profit=50)                    // Since the long1 entry order is not filled, the exit order with ID exit1 is also on hold until the corresponding entry order is filled before exit1 is placed
    strategy.exit("exit2", "long2", qty=0.1, profit=100)          // Specify the parameter qty to close 0.1 positions in the position with ID long2
    strategy.exit("exit3", "long3", qty_percent=50, limit=strategy.opentrades.entry_price(findOrderIdx("long3")) + 1000)   // Specify the parameter qty_percent to close 50% of the positions in the position with ID long3
    isExit := true 

if bar_index == 0 
    runtime.log("The price per point:", syminfo.mintick)    // The price per point is related to the "Pricing Currency Precision" parameter setting on the Pine language template parameters

আমরা ব্যাকটেস্টের জন্য রিয়েল-টাইম মূল্য মডেল ব্যবহার করি, পরীক্ষার কৌশলটি 3 টি প্রবেশ অপারেশন দিয়ে শুরু হয় (strategy.entryফাংশন) এবংlong1ইচ্ছাকৃতভাবেlimitপরামিতি একটি অপেক্ষমান অর্ডার মূল্য 1 সঙ্গে, তাই এটি পূরণ করা যাবে না. তারপর শর্তাধীন প্রস্থান ফাংশন পরীক্ষাstrategy.exitআমরা পয়েন্ট দ্বারা মুনাফা গ্রহণ এবং মূল্য দ্বারা মুনাফা গ্রহণ ব্যবহার করেছি, একটি নির্দিষ্ট সংখ্যক অবস্থান বন্ধ, এবং শতাংশ দ্বারা বন্ধ অবস্থান। উদাহরণ দৈর্ঘ্য দেওয়া, শুধুমাত্র লাভ গ্রহণ প্রদর্শিত হয়। স্টপ-হ্রাস অপারেশন একই।strategy.exitফাংশন আরো জটিল ট্রেইলিং স্টপ পরামিতি আছেঃtrail_price, trail_points, trail_offsetতাদের ব্যবহার শিখতে এই উদাহরণে পরীক্ষা করা যেতে পারে।


  1. strategy.cancel

দ্যstrategy.cancelফাংশনগুলি সমস্ত প্রাক-অপেন্ডিং অর্ডার বাতিল / বন্ধ করতে ব্যবহৃত হয়। এই ফাংশনগুলিঃstrategy.order, strategy.entry , strategy.exitএন্ট্রি আইডি তৈরি করতে পারে। এই ফাংশনের প্রধান পরামিতি হলঃid, when.

পরামিতিঃ

  • id: ভর্তি আইডি বাতিল করা হবে।
  • when: কার্যকরকরণের শর্তাবলী।

এই ফাংশনটি বোঝা সহজ, এবং এটি পূরণ না করা এন্ট্রি অর্ডার বাতিল করতে ব্যবহৃত হয়।

/*backtest
start: 2022-07-03 00:00:00
end: 2022-07-09 00:00:00
period: 1d
basePeriod: 1h
exchanges: [{"eid":"Binance","currency":"BTC_USDT"}]
*/

strategy("strategy.cancel Demo", pyramiding=3)

var isStop = false 
if isStop 
    runtime.error("stop")

strategy.entry("long1", strategy.long, 0.1, limit=1)
strategy.entry("long2", strategy.long, 0.2, limit=2)
strategy.entry("long3", strategy.long, 0

আরো