Scaled Order Sizing and Take Profit Target Arrays
//  This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
//  © kaigouthro

// @version=5
// @ description # WOAH Order Scaling!
// This Provides a user with methods to create a list of profit targets
// and order sizes which grow or shrink. 
// #### For size
// - they will add up to the specified sum.
// #### For Targets 
// - will include the first and last
// >
//  `weight` leans towards start or end
// 
library('weighted_order_array_handler')

import kaigouthro/calc/6

// @type Target Objects contain Informations for the order placement
// @field price  The  price for the order
// @field size   The size for the order
// @field ispct_prc  Is the price a percentage
// @field ispct_sz   Is the size a percentage
export type target
    float price      = close
    float size       = 0
    bool  ispct_prc  = false
    bool  ispct_sz   = false

//  @function # Weighted array off sizes
//  ----
//  create an array of sizes which grow or shrink from first to last
//  which add up to 1.0 if set the as_percent flag , or a total value / sum.
//  ### `example`
//  ```
//  total_size = input(100, 'USD order size') / close
//  count      = input(5  , 'Order count')
//  weight     = input(100, 'Grow/Shrink') / 100
//  min_size   = input(10, ' Min Required Order')  / close
//  array<float> split = scaled_sizes(total_size, count, weight, min_size)
//  ```
//  @param 	 total_size (float)  total size to divide ito split
//  @param 	 count      (int  )  desired number of splits to create
//  @param 	 weight     (float)  a weight to apply to grow or shrink the split either towards the last being most, or the first being most, or 1.0 being each is equally sized as  1/n count
//  @param 	 min_size   (float)  a minimum size for the smallest value (in value of ttotal_size units)
//  @param 	 as_percent (float)  a minimum size for the smallest value (in value of ttotal_size units)
//  @returns  Array of   Sizes for each split
export method scaled_sizes(float total_size, int count,float weight, float min_size, bool as_percent = false) =>   
    size = total_size / count        //  @variable calculate the size of each
    sizes = array.new<float>(count)  //  @variable list of sizes
    for i = 0 to count -1            //  calculate the size of each
        sizes.set(i, size)   
    for i = 0 to count -1            //  apply the weight to the sizes
        sizes.set(i, sizes.get(i) * math.pow(weight,i+1))   
    for i = 0 to count -1            //  apply the min size to the sizes
        if sizes.get(i) < min_size
            sizes.set(i, min_size)
    sum = sizes.sum()   
    for i = 0 to count -1            //  calculate the percentage of the sizes
        sizes.set(i, sizes.get(i)/sum * (as_percent ? 1 : total_size))
    sizes


//  @function # Create Profit Targets
//  ----
//  create a list of take profitt targets from the smallest to larget distance
//  ### `example`
//  ```
//  targets = input.int  (5,'Profit targets')
//  weight  = input.float(1,'TP Weight (1.0 = equal growth per step)', 0.1,2, step = 0.1)
//  min_tp  = input.float(0.1,'First TP')/100
//  max_tp  = input.float(0.55,'LKast TP')/100
//  // Call
//  array<float> targets = scaled_targets(targets,weight,min_tp,max_tp)
// 
//  ```
//  @param 	 count   (int  ) number of targets
//  @param 	 weight  (float) weight to apply to growing or shrinking
//  @param 	 minimum (float) first value of the output
//  @param 	 maximum (float) last value of the output
//  @returns  Array percentage targets
export method scaled_targets(int count, float weight, float minimum, float maximum) =>
    split = scaled_sizes(calc.gapSize(maximum,minimum), count-1, weight, 0)  //  create a list of sizes
    targets = array.new<float>(count)                            //  create a list of targets
    for i = 0 to count -1                                        //  calculate the size of each
        targets.set(i, minimum + split.slice(0,i).sum())
    targets


// @function # Creates target Objects with combined info.
//  ----
//  Creates a list of take profitt targets from the smallest to larget distance
//  and a set of sizes for each which add up to the total size 
//  Combines them into Target OPbjecs
//  ### `example`
//  ```
//  total_size = input(100, 'USD order size') / close
//  count      = input(5  , 'Order count')
//  tp_weight  = input(100, 'Grow/Shrink') / 100
//  tp_min     = input(10, ' Min TP')  / 100
//  tp_max     = input(0.55, 'Max TP')  / 100
//  size_weight = input(100, 'Grow/Shrink') / 100
//  min_size   = input(10, ' Min Required Order')  / close
//  // Call
//  scaled_order_array(total_size, count, tp_weight, tp_min, tp_max, size_weight, min_size)
// 
//  ```
//  @param 	 total_size   (float) total size to divide ito split
//  @param 	 count        (int  ) desired number of splits to create
//  @param 	 tp_weight    (float) a weight to apply to grow or shrink the target prices
//  @param 	 tp_min       (float) a minimum target 
//  @param 	 tp_max       (float) a maximum target
//  @param 	 size_weight  (float) a weight to apply to grow or shrink the split either towards the last being most, or the first being most, or 1.0 being each is equally sized as  1/n count
//  @param 	 min_size     (float) a minimum size for the smallest value (in value of ttotal_size units)
//  @param 	 as_percent   (bool) Use percent for size
//  @returns  Array of   Sizes for each split
export method scaled_order_array(float total_size, int count, float tp_weight, float tp_min, float tp_max, float size_weight, float min_size, bool as_percent = false) =>
    array<float>  targets = scaled_targets(count, tp_weight, tp_min, tp_max)
    array<float>  sizes   = scaled_sizes(total_size, count, size_weight, min_size, as_percent)
    array<target> order_array = array.new<target>(count)
    for i = 0 to count -1
        order_array.set(i, target.new(price = targets.get(i), size = sizes.get(i), ispct_prc = true, ispct_sz = as_percent))
    order_array

