Having trouble getting my average true range program to work

im am trying to create a program, to return 15 days of a stock with the high, lows, close, and open. now all that works, what doesnt work is calculating the true range of a stock

these are the conditions
1.
The distance from today’s high to today’s low
2.
The distance from yesterday’s close to today’s high
3.
The distance from yesterday’s close to today’s low

these are the conditions that i want the program to calculate and then return the high number with absolute value of all numbers, now only the first condition works. its the last two because program is not holding the previous days close value properly in order for the equation to take place

i will only post the code if someone is willing to help, i want to explain a little of the bit of the situation without bombarding someone.

thanks

Are you encountering any specific error messages or unexpected behavior? Share the exact wording if possible.

its a calculation behaviour issue

here are the results
Date Open High Low Close preclose TR
2024-01-26 72.25 73.19 70.45 71.28 73.37 2.73
2024-01-29 71.69 73.09 70.78 73.03 68.87 2.31
2024-01-30 73.01 73.62 70.86 71.43 63.40 2.76
2024-01-31 69.74 70.87 68.24 68.53 66.22 2.63
2024-02-01 68.87 69.30 67.66 68.15 55.63 1.64
2024-02-02 67.90 69.06 67.33 68.85 57.23 1.73
2024-02-05 69.15 69.89 67.97 68.37 56.17 1.92
2024-02-06 62.55 62.55 54.82 55.26 53.62 7.73
2024-02-07 55.60 56.21 53.11 53.62 67.38 3.10
2024-02-08 53.81 57.36 53.81 56.25 65.38 3.55
2024-02-09 56.89 59.14 56.80 58.70 54.19 2.35
2024-02-12 58.80 59.74 57.66 58.04 69.35 2.08
2024-02-13 55.03 56.56 54.17 55.22 57.02 2.39
2024-02-14 56.30 57.18 55.57 57.02 66.28 1.61
2024-02-15 57.38 57.58 55.59 56.34 66.70 1.98

now basically, i send a copy of the code, but basically i think the api work properly because it gets the proper values high, close of a stock on a particular day, however my code is not storing the last close day properly for the calculation of the next day. bascially i showed here in the output how the prevclose is not equal to the close, and therefore the calculation is off. with how the true range works, its based on three conditions and the higher number of the 3 conditions becomes the true range and my two conditions are off because of the wrong close value of the previous day

here is my code, now i use two code script. the main script which contain all the functions and calculations and the atr script which does the calculation and bit just for the average true range and true range

main script
package main

import (
“encoding/json”
“fmt”
“net/http”
“strconv”
“time”

atr "example/golang/ATR" // Update with your package path

)

const apiKey = “HBCPDZ4Q7P5W4QNX”
const symbol = “RMBS”

type Candle struct {
High float64
Low float64
Close float64
}

type TimeSeries Candle

func NewTimeSeries(data map[string]interface{}) (TimeSeries, error) {
var series TimeSeries

timeSeriesData, ok := data["Time Series (Daily)"].(map[string]interface{})
if !ok {
	return nil, fmt.Errorf("missing or invalid 'Time Series (Daily)' field in data")
}

for date, dailyData := range timeSeriesData {
	dailyDataMap, ok := dailyData.(map[string]interface{})
	if !ok {
		return nil, fmt.Errorf("unexpected data format for date %s: %+v", date, dailyData)
	}

	high, _ := strconv.ParseFloat(dailyDataMap["2. high"].(string), 64)
	low, _ := strconv.ParseFloat(dailyDataMap["3. low"].(string), 64)
	close, _ := strconv.ParseFloat(dailyDataMap["4. close"].(string), 64)

	candle := Candle{High: high, Low: low, Close: close}
	series = append(series, candle)
}

// Reverse the series to have the latest date first
for i, j := 0, len(series)-1; i < j; i, j = i+1, j-1 {
	series[i], series[j] = series[j], series[i]
}

return series, nil

}

func main() {
url := fmt.Sprintf(“https://www.alphavantage.co/query?function=TIME_SERIES_DAILY&symbol=%s&apikey=%s”, symbol, apiKey)
response, err := http.Get(url)
if err != nil {
panic(err)
}
defer response.Body.Close()

var data map[string]interface{}
err = json.NewDecoder(response.Body).Decode(&data)
if err != nil {
	panic(err)
}

series, err := NewTimeSeries(data)
if err != nil {
	panic(err)
}

fmt.Printf("%-12s%-12s%-12s%-12s%-12s%-12s%-12s\n", "Date", "Open", "High", "Low", "Close", "preclose", "TR")

// Calculate TR and print data for the last 15 trading days
atrSum := 0.0
validDays := 0
var trValues []float64
for i := 15; i > 0; i-- {
	date := getDateNdaysAgo(i)
	dailyData, ok := data["Time Series (Daily)"].(map[string]interface{})[date].(map[string]interface{})
	if !ok {
		// Skip weekends or non-trading days
		continue
	}

	open, _ := strconv.ParseFloat(dailyData["1. open"].(string), 64)
	high, _ := strconv.ParseFloat(dailyData["2. high"].(string), 64)
	low, _ := strconv.ParseFloat(dailyData["3. low"].(string), 64)
	close, _ := strconv.ParseFloat(dailyData["4. close"].(string), 64)

	prevClose := getPreviousClose(series, i)

	//highLowDiff := high - low
	//highCloseDiff := high - close
	//lowCloseDiff := low - close

	tr := atr.CalculateTrueRange(high, low, close)

	fmt.Printf("%-12s%-12.2f%-12.2f%-12.2f%-12.2f%-12.2f%-12.2f\n", date, open, high, low, close, prevClose, tr)

	if i > 0 {
		atrSum += tr
		validDays++
		trValues = append(trValues, tr)
	}
}

// Calculate ATR
atr := atr.CalculateATR(trValues, validDays)
fmt.Printf("\nAverage True Range (ATR) for the last %d trading days: %.2f\n", validDays, atr)

}

func getPreviousClose(series TimeSeries, index int) float64 {
//if index == 15 {
//return series[index].Close
//}
return series[index].Close
}

func getDateNdaysAgo(n int) string {
today := time.Now()
for i := 0; i <= n; {
previousDate := today.AddDate(0, 0, -i)
if previousDate.Weekday() == time.Saturday || previousDate.Weekday() == time.Sunday {
// Skip weekends
today = today.AddDate(0, 0, -1)
continue
}
i++
}
previousDate := today.AddDate(0, 0, -n)
return previousDate.Format(“2006-01-02”)
}
package main

import (
“encoding/json”
“fmt”
“net/http”
“strconv”
“time”

atr "example/golang/ATR" // Update with your package path

)

const apiKey = "I know the api key "
const symbol = “RMBS”

type Candle struct {
High float64
Low float64
Close float64
}

type TimeSeries Candle

func NewTimeSeries(data map[string]interface{}) (TimeSeries, error) {
var series TimeSeries

timeSeriesData, ok := data["Time Series (Daily)"].(map[string]interface{})
if !ok {
	return nil, fmt.Errorf("missing or invalid 'Time Series (Daily)' field in data")
}

for date, dailyData := range timeSeriesData {
	dailyDataMap, ok := dailyData.(map[string]interface{})
	if !ok {
		return nil, fmt.Errorf("unexpected data format for date %s: %+v", date, dailyData)
	}

	high, _ := strconv.ParseFloat(dailyDataMap["2. high"].(string), 64)
	low, _ := strconv.ParseFloat(dailyDataMap["3. low"].(string), 64)
	close, _ := strconv.ParseFloat(dailyDataMap["4. close"].(string), 64)

	candle := Candle{High: high, Low: low, Close: close}
	series = append(series, candle)
}

// Reverse the series to have the latest date first
for i, j := 0, len(series)-1; i < j; i, j = i+1, j-1 {
	series[i], series[j] = series[j], series[i]
}

return series, nil

}

func main() {
url := fmt.Sprintf(“https://www.alphavantage.co/query?function=TIME_SERIES_DAILY&symbol=%s&apikey=%s”, symbol, apiKey)
response, err := http.Get(url)
if err != nil {
panic(err)
}
defer response.Body.Close()

var data map[string]interface{}
err = json.NewDecoder(response.Body).Decode(&data)
if err != nil {
	panic(err)
}

series, err := NewTimeSeries(data)
if err != nil {
	panic(err)
}

fmt.Printf("%-12s%-12s%-12s%-12s%-12s%-12s%-12s\n", "Date", "Open", "High", "Low", "Close", "preclose", "TR")

// Calculate TR and print data for the last 15 trading days
atrSum := 0.0
validDays := 0
var trValues []float64
for i := 15; i > 0; i-- {
	date := getDateNdaysAgo(i)
	dailyData, ok := data["Time Series (Daily)"].(map[string]interface{})[date].(map[string]interface{})
	if !ok {
		// Skip weekends or non-trading days
		continue
	}

	open, _ := strconv.ParseFloat(dailyData["1. open"].(string), 64)
	high, _ := strconv.ParseFloat(dailyData["2. high"].(string), 64)
	low, _ := strconv.ParseFloat(dailyData["3. low"].(string), 64)
	close, _ := strconv.ParseFloat(dailyData["4. close"].(string), 64)

	prevClose := getPreviousClose(series, i)

	//highLowDiff := high - low
	//highCloseDiff := high - close
	//lowCloseDiff := low - close

	tr := atr.CalculateTrueRange(high, low, close)

	fmt.Printf("%-12s%-12.2f%-12.2f%-12.2f%-12.2f%-12.2f%-12.2f\n", date, open, high, low, close, prevClose, tr)

	if i > 0 {
		atrSum += tr
		validDays++
		trValues = append(trValues, tr)
	}
}

// Calculate ATR
atr := atr.CalculateATR(trValues, validDays)
fmt.Printf("\nAverage True Range (ATR) for the last %d trading days: %.2f\n", validDays, atr)

}

func getPreviousClose(series TimeSeries, index int) float64 {
//if index == 15 {
//return series[index].Close
//}
return series[index].Close
}

func getDateNdaysAgo(n int) string {
today := time.Now()
for i := 0; i <= n; {
previousDate := today.AddDate(0, 0, -i)
if previousDate.Weekday() == time.Saturday || previousDate.Weekday() == time.Sunday {
// Skip weekends
today = today.AddDate(0, 0, -1)
continue
}
i++
}
previousDate := today.AddDate(0, 0, -n)
return previousDate.Format(“2006-01-02”)
}

atr script
// atr.go
package atr

import (
“math”
)

// CalculateTrueRange calculates the True Range (TR) for a given candle.
func CalculateTrueRange(high, low, close float64) float64 {
highLowDiff := high - low

// theses are wrong, both highclose and lowclose
highCloseDiff := math.Abs(high - close)
lowCloseDiff := math.Abs(low - close)

//fmt.Printf("high-low difference: %.2f\n", highLowDiff)
//fmt.Printf("high-Close difference: %.2f\n", highCloseDiff)
//fmt.Printf("low-close difference: %.2f\n", lowCloseDiff)
tr := highLowDiff
if highCloseDiff > tr {
	tr = highCloseDiff
}
if lowCloseDiff > tr {
	tr = lowCloseDiff
}

return tr

}

// CalculateATR calculates the Average True Range (ATR) for a given series of TR values and a period.
func CalculateATR(trValues float64, period int) float64 {
// Ensure we don’t exceed the length of trValues
if len(trValues) < period {
period = len(trValues)
}

var sum float64
for i := len(trValues) - period; i < len(trValues); i++ {
	sum += trValues[i]
}

return sum / float64(period)

}