Golang : Scan forex opportunities by Bollinger bands
My previous post of using Golang to create a scanner to spot opportunities is base on RSI criteria. For this post, we will learn how to scan with another method. We will detect if any given cross breach the upper or lower Bollinger Bands.
Here you go!
package main
import (
"fmt"
"strconv"
"strings"
"time"
"github.com/awoldes/goanda"
"github.com/markcheno/go-talib"
)
func main() {
oandaAccountID := ""
oandaAPIKey := ""
// set the NewConnection 3rd parameter to [false] to use DEMO account.
// [true] for LIVE account
fmt.Println("Starting Oanda Trading bot....")
UsingLIVEAccount := false // set false to use https://api-fxpractice.oanda.com
oanda := goanda.NewConnection(oandaAccountID, oandaAPIKey, UsingLIVEAccount)
temp := "USD_DKK,EUR_AUD,CHF_JPY,EUR_SGD,USD_JPY,EUR_TRY,USD_CZK,GBP_AUD,USD_PLN,USD_SGD,EUR_SEK,USD_HKD,EUR_NZD,SGD_JPY,AUD_CAD,GBP_CHF,USD_THB,TRY_JPY,CHF_HKD,AUD_USD,EUR_DKK,EUR_USD,AUD_NZD,SGD_HKD,EUR_HUF,USD_CNH,EUR_HKD,EUR_JPY,NZD_USD,GBP_PLN,GBP_JPY,USD_TRY,EUR_CAD,USD_SEK,GBP_SGD,EUR_GBP,GBP_HKD,USD_ZAR,AUD_CHF,USD_CHF,USD_MXN,GBP_USD,EUR_CHF,EUR_NOK,AUD_SGD,CAD_CHF,SGD_CHF,CAD_HKD,USD_INR,NZD_CAD,GBP_ZAR,NZD_SGD,ZAR_JPY,CAD_JPY,GBP_CAD,USD_SAR,NZD_CHF,NZD_HKD,GBP_NZD,AUD_HKD,EUR_CZK,CHF_ZAR,USD_HUF,NZD_JPY,HKD_JPY,CAD_SGD,USD_NOK,USD_CAD,AUD_JPY,EUR_PLN,EUR_ZAR"
// first, clean/remove the comma
cleaned := strings.Replace(temp, ",", " ", -1)
// crosses to monitor
crossesToMonitor := strings.Fields(cleaned)
fmt.Println("Crosses to monitor : ")
fmt.Println(crossesToMonitor)
// Scan by Bollinger Bands
go ScanCrossByBBands(oanda, crossesToMonitor, 16)
select {} // this will cause the program to run forever until termination
}
//--------------------------------------------------------------------------------------------------------
func GetPrice(oanda *goanda.OandaConnection, cross string) float64 {
instrument := cross
priceResponse := oanda.GetInstrumentPrice(instrument)
//askPrice := strconv.FormatFloat(priceResponse.Prices[0].Asks[0].Price, 'f', 6, 64)
//bidPrice := strconv.FormatFloat(priceResponse.Prices[0].Bids[0].Price, 'f', 6, 64)
//queryTime := priceResponse.Prices[0].Time
//result := "Asking price at [" + queryTime.String() + "] is " + askPrice + ".Bidding price is " + bidPrice + "."
//return result
return priceResponse.Prices[0].Bids[0].Price
}
func ScanCrossByBBands(oanda *goanda.OandaConnection, crosses []string, intervalSecond int) {
counter := time.Tick(time.Duration(intervalSecond) * time.Second) // poll every 16 seconds
for range counter {
for k, v := range crosses {
currentUpper, currentMiddle, currentLower := GetOneHourBBands(oanda, v)
upperStr := strconv.FormatFloat(currentUpper, 'f', 6, 64) // convert float64 to string
middleStr := strconv.FormatFloat(currentMiddle, 'f', 6, 64) // convert float64 to string
lowerStr := strconv.FormatFloat(currentLower, 'f', 6, 64) // convert float64 to string
fmt.Println(k, v, "Bollinger Bands - Upper : "+upperStr+", Middle(Basis) : "+middleStr+", Lower : "+lowerStr)
// alert if this particular cross BBands higher or lower than BBands
currentPrice := GetPrice(oanda, v)
if currentPrice >= currentUpper {
currentPriceStr := strconv.FormatFloat(currentUpper, 'f', 6, 64) // convert float64 to string
fmt.Println(k, v, " price is "+currentPriceStr+" and breached upper band. [**SHORT**]")
}
if currentPrice <= currentLower {
currentPriceStr := strconv.FormatFloat(currentUpper, 'f', 6, 64) // convert float64 to string
fmt.Println(k, v, " price is "+currentPriceStr+" and breached lower band. [**LONG**]")
}
}
}
}
func GetOneHourBBands(oanda *goanda.OandaConnection, cross string) (float64, float64, float64) {
// See http://developer.oanda.com/rest-live-v20/instrument-ep/#collapse_2_example_curl_1
// and for the candlestick granularity ... see
// http://developer.oanda.com/rest-live-v20/instrument-df/#CandlestickGranularity
// Get 100 candles with 1 hour granularity
data := oanda.GetCandles(cross, "100", "H1") // H1 = 1 hour
closeSlice := make([]float64, len(data.Candles))
// calculate BBands
for i := 0; i < len(data.Candles); i++ {
closeSlice[i] = data.Candles[i].Mid.Close
}
// source = close, length=20, stddev=2, offset = 0
upper, middle, lower := talib.BBands(closeSlice, 20, 2.0, 2.0, 0)
// instead of a slice of values for plotting graph, we only interested in the current value
return upper[len(upper)-1], middle[len(middle)-1], lower[len(lower)-1]
// return this if you want to plot graph
//return talib.BBands(closeSlice, 20, 2, 2, 0)
}
Sample output:
0 USD_DKK Bollinger Bands - Upper : 6.568570, Middle(Basis) : 6.556630, Lower : 6.544689
1 EUR_AUD Bollinger Bands - Upper : 1.588591, Middle(Basis) : 1.585088, Lower : 1.581585
2 CHF_JPY Bollinger Bands - Upper : 110.766608, Middle(Basis) : 110.600800, Lower : 110.434992
2 CHF_JPY price is 110.766608 and breached lower band. [LONG]
3 EUR_SGD Bollinger Bands - Upper : 1.535802, Middle(Basis) : 1.534125, Lower : 1.532447
4 USD_JPY Bollinger Bands - Upper : 110.841978, Middle(Basis) : 110.617900, Lower : 110.393822
4 USD_JPY price is 110.841978 and breached lower band. [LONG]
5 EUR_TRY Bollinger Bands - Upper : 6.053541, Middle(Basis) : 6.041364, Lower : 6.029188
6 USD_CZK Bollinger Bands - Upper : 22.602139, Middle(Basis) : 22.533306, Lower : 22.464473
7 GBP_AUD Bollinger Bands - Upper : 1.847077, Middle(Basis) : 1.844400, Lower : 1.841723
8 USD_PLN Bollinger Bands - Upper : 3.809006, Middle(Basis) : 3.800306, Lower : 3.791607
9 USD_SGD Bollinger Bands - Upper : 1.349430, Middle(Basis) : 1.348080, Lower : 1.346729
10 EUR_SEK Bollinger Bands - Upper : 10.585036, Middle(Basis) : 10.574920, Lower : 10.564804
11 USD_HKD Bollinger Bands - Upper : 7.849623, Middle(Basis) : 7.849112, Lower : 7.848601
12 EUR_NZD Bollinger Bands - Upper : 1.653353, Middle(Basis) : 1.651515, Lower : 1.649677
13 SGD_JPY Bollinger Bands - Upper : 82.175845, Middle(Basis) : 82.056150, Lower : 81.936455
13 SGD_JPY price is 82.175845 and breached lower band. [LONG]
14 AUD_CAD Bollinger Bands - Upper : 0.947366, Middle(Basis) : 0.946222, Lower : 0.945078
See also : Golang : Find correlation coefficient example
By Adam Ng(黃武俊)
IF you gain some knowledge or the information here solved your programming problem. Please consider donating to the less fortunate or some charities that you like. Apart from donation, planting trees, volunteering or reducing your carbon footprint will be great too.
Advertisement
Tutorials
+12.1k Golang : "https://" not allowed in import path
+10.9k Golang : How to pipe input data to executing child process?
+39.1k Golang : Remove dashes(or any character) from string
+4.6k HTTP common errors and their meaning explained
+5.8k Golang : How to write backslash in string?
+34.8k Golang : Integer is between a range
+13.9k Golang : How to convert a number to words
+26.3k Golang : Convert file content into array of bytes
+10.3k Golang : Bubble sort example
+14.2k Golang : Overwrite previous output with count down timer