Technical Analysis Library for Golang

Techan

codecov

TechAn is a technical analysis library for Go! It provides a suite of tools and frameworks to analyze financial data and make trading decisions.

Features

  • Basic and advanced technical analysis indicators
  • Profit and trade analysis
  • Strategy building

Installation

$ go get github.com/sdcoffey/techan

Quickstart

series := techan.NewTimeSeries()

// fetch this from your preferred exchange
dataset := [][]string{
	// Timestamp, Open, Close, High, Low, volume
	{"1234567", "1", "2", "3", "5", "6"},
}

for _, datum := range dataset {
	start, _ := strconv.ParseInt(datum[0], 10, 64)
	period := techan.NewTimePeriod(time.Unix(start, 0), time.Hour*24)

	candle := techan.NewCandle(period)
	candle.OpenPrice = big.NewFromString(datum[1])
	candle.ClosePrice = big.NewFromString(datum[2])
	candle.MaxPrice = big.NewFromString(datum[3])
	candle.MinPrice = big.NewFromString(datum[4])

	series.AddCandle(candle)
}

closePrices := techan.NewClosePriceIndicator(series)
movingAverage := techan.NewEMAIndicator(closePrices, 10) // Create an exponential moving average with a window of 10

fmt.Println(movingAverage.Calculate(0).FormattedString(2))

Creating trading strategies

indicator := techan.NewClosePriceIndicator(series)

// record trades on this object
record := techan.NewTradingRecord()

entryConstant := techan.NewConstantIndicator(30)
exitConstant := techan.NewConstantIndicator(10)

// Is satisfied when the price ema moves above 30 and the current position is new
entryRule := techan.And(
	techan.NewCrossUpIndicatorRule(entryConstant, indicator),
	techan.PositionNewRule{})
	
// Is satisfied when the price ema moves below 10 and the current position is open
exitRule := techan.And(
	techan.NewCrossDownIndicatorRule(indicator, exitConstant),
	techan.PositionOpenRule{})

strategy := techan.RuleStrategy{
	UnstablePeriod: 10, // Period before which ShouldEnter and ShouldExit will always return false
	EntryRule:      entryRule,
	ExitRule:       exitRule,
}

strategy.ShouldEnter(0, record) // returns false

Credits

Techan is heavily influenced by the great ta4j. Many of the ideas and frameworks in this library owe their genesis to the great work done over there.

License

Techan is released under the MIT license. See LICENSE for details.

Owner
Comments
  • Something wrong how RSI is calculated

    Something wrong how RSI is calculated

    I can't say for sure what's wrong (I'm not familiar how RSI is calculated), but the calculation itself is not providing the right result when I compare to what I see on Tradingview. To triple-check I was not doing something wrong, I tried with this library https://github.com/markcheno/go-talib, which provided the expected result.

    Also I'm using successfully the EMA of this library, which works well, so I highly suspect that the RSI calculation is not correct.

  • Corrected EMA formula for window != 3

    Corrected EMA formula for window != 3

    According to https://tlc.thinkorswim.com/center/reference/Tech-Indicators/studies-library/M-N/MovAvgExponential

    The recursive formula for EMA is the following:

    EMA_1 = price_1;
    EMA_2 = α*price_2 + (1 - α)*EMA_1;
    EMA_3 = α*price_3 + (1 - α)*EMA_2;
    EMA_N = α*price_N + (1 - α)*EMA_N-1;
    

    The original test didn't fail because with a window size of 3 the alpha value is 0.5 and therefore the formula was working in that case. I've added a test with a different window size that illustrates the problem.

    Without this fix, the new test case fails with clearly incorrect values:

                                    Diff:
                                    --- Expected
                                    +++ Actual
                                    @@ -6,9 +6,9 @@
                                      (float64) 63.91,
                                    - (float64) 63.67,
                                    - (float64) 63.75,
                                    - (float64) 63.7833,
                                    - (float64) 63.5056,
                                    - (float64) 63.4604,
                                    - (float64) 62.7502,
                                    - (float64) 62.3368
                                    + (float64) 42.3667,
                                    + (float64) 35.4256,
                                    + (float64) 33.0919,
                                    + (float64) 32.014,
                                    + (float64) 31.7947,
                                    + (float64) 31.0416,
                                    + (float64) 30.8505
                                     }
    
  • Representing NA values

    Representing NA values

    Hi! I think it's useful to have a special NA or NaN value to represent the case where a value cannot be calculated. Other popular data analysis libraries such like numpy/pandas all have it.

    One use case is that I want to calculate the difference between today's close price and yesterday's close price for each candle in the time series. Then I want to do dif := techan.NewDifferenceIndicator(today, NewRefIndicator(yday, 1)) but if I accidentally call dif.Calculate(0) it will segfault.

    I think we can workaround this problem by other means but I feel the most natural way is to add a NA value. What's your thoughts on this?

  • should EMA consider time window?

    should EMA consider time window?

    Hi, I see the implementation of EMA does not consider the time window, is it correct? https://github.com/sdcoffey/techan/blob/572c478f546ecfef27a8454bd653f95829269490/indicator_exponential_moving_average.go#L24-L37

    Also, is RSI correct since RSI relays on EMA?

  • Question: What do you guys mean by window?

    Question: What do you guys mean by window?

    	ema := NewEMAIndicator(NewClosePriceIndicator(ts), 10)
    
    	decimalEquals(t, 63.6948, ema.Calculate(9))
    	decimalEquals(t, 63.2649, ema.Calculate(10))
    	decimalEquals(t, 62.9458, ema.Calculate(11))
    

    ts variable has a time-period set for candles already. So what is this window parameter passed to NewEMAIndicator? Also, what is the purpose of that parameter index given to Calculate?

    I couldn't find any documentation for it. Can someone please explain it to me?

  • TimeSeries holding candles infinitely?

    TimeSeries holding candles infinitely?

    I'm running a server which appends candles to a techan.TimeSeries struct. Since I can't save the candles forever(if so, Out Of Memory will make me crazy), I'm throwing away the old ones if a new candle is appended(for example, if len(timeSeries.Candles) > 200, I throw up the old ones to hold only 200 candles). I'll call my candles` slice MyBuffer. The problem is: if I run MACD, it gives me the same value for every new candle appended. And the reason I analysed is this: https://github.com/sdcoffey/techan/blob/018e9f93c71ae6ddf483cb7a53689db12a8d3c4e/indicator_moving_average.go#L48 The ema.resultCache's result is returned, since the size of the cache is set to be very large and MyBuffer is much more small, therefore always passing the condition to return the cached value.

    Is setting MyBuffer's size the only way to solve this situation? Or is there other graceful way to this problem?

  • does profit analyze support future?

    does profit analyze support future?

    I found some profile analyze use exitvalue sub costbaseis, but in future, you could sell short first and then buy long. does the profit analyze with order side?

  • support trading record of database

    support trading record of database

    what's a wonderful project! It's great! can it support load trading recorde data from database/log file and save trading record data to database/log file? then analysis this offline data satisfied.

  • Checkout-Java-SDK

    Checkout-Java-SDK

    Hello, Steve Coffey! What is the difference between PayPal Orders API and Payments API from Checkout-Java-SDK? Which one to use if I want to use authentications? It is seems that Orders API not allows doing void of authorization. It feels like Order API is for use cases where you want to capture instantly and Payments API is for use cases when you want to use authorization, but it's not clear for me yet, am I right?

    Orders API https://developer.paypal.com/docs/api/orders/v2/

    Payments API https://developer.paypal.com/docs/api/payments/v2/

  • Macd Signal

    Macd Signal

    How to obtain the macd signal?

    In the tests, one can only obtain the macd and macd histogram values

    package techan
    
    import (
    	"testing"
    
    	"github.com/stretchr/testify/assert"
    )
    
    func TestNewMACDIndicator(t *testing.T) {
    	series := randomTimeSeries(100)
    
    	macd := NewMACDIndicator(NewClosePriceIndicator(series), 12, 26)
    
    	assert.NotNil(t, macd)
    }
    
    func TestNewMACDHistogramIndicator(t *testing.T) {
    	series := randomTimeSeries(100)
    
    	macd := NewMACDIndicator(NewClosePriceIndicator(series), 12, 26)
    	macdHistogram := NewMACDHistogramIndicator(macd, 9)
    
    	assert.NotNil(t, macdHistogram)
    }
    

    Any thoughts ?

  • Fix EMA calulation when window > 3

    Fix EMA calulation when window > 3

    There is a bug in EMA calculations when window is > 3. Consequently, the test case didn't pick it up as it only used a window of 3.

    This PR fixes the EMA by correcting the (1 - alpha) component of the calculation as per https://www.investopedia.com/terms/e/ema.asp ..

  • Cashing in indicators

    Cashing in indicators

    Hey! I had a problem recalculating the last value of a series due to result caching. I want to propose to take out the need to use the cache for the flag. What do you think of it?

    for example

  • SMA Bug in v0.12.1 ?

    SMA Bug in v0.12.1 ?

    package main
    
    import (
    	"fmt"
    	"time"
    
    	"github.com/sdcoffey/big"
    	"github.com/sdcoffey/techan"
    )
    
    func calcSma(series *techan.TimeSeries, days int) []big.Decimal {
    	closePrices := techan.NewClosePriceIndicator(series)
    	sma := techan.NewSimpleMovingAverage(closePrices, days)
    
    	cnt := len(series.Candles)
    	ret := make([]big.Decimal, cnt)
    	for idx := range ret {
    		ret[idx] = sma.Calculate(idx)
    	}
    	return ret
    }
    
    func main() {
    	series := techan.NewTimeSeries()
    	for i := 1; i <= 30; i++ {
    		day := time.Date(2020, 5, i, 0, 0, 0, 0, time.Local)
    		candle := techan.NewCandle(techan.TimePeriod{
    			Start: day,
    			End:   day.Add(time.Duration(23) * time.Hour),
    		})
    
    		candle.ClosePrice = big.NewDecimal(float64(100 + i))
    		added := series.AddCandle(candle)
    		if !added {
    			fmt.Println("AddCandle failed")
    			return
    		}
    	}
    
    	indicators := calcSma(series, 10)
    	fmt.Println("SMA:", indicators)
    }
    

    with version 0.12.0

    module main
    
    go 1.17
    
    require (
    	github.com/sdcoffey/big v0.7.0
    	github.com/sdcoffey/techan v0.12.0
    )
    

    the program run result is: SMA: [101 101.5 102 102.5 103 103.5 104 104.5 105 105.5 106.5 107.5 108.5 109.5 110.5 111.5 112.5 113.5 114.5 115.5 116.5 117.5 118.5 119.5 120.5 121.5 122.5 123.5 124.5 125.5]

    I think above result is correct, but with v0.12.1

     module main
    
    go 1.17
    
    require (
    	github.com/sdcoffey/big v0.7.0
    	github.com/sdcoffey/techan v0.12.1
    )
    

    the result is: SMA: [0 0 0 0 0 0 0 0 0 105.5 106.5 107.5 108.5 109.5 110.5 111.5 112.5 113.5 114.5 115.5 116.5 117.5 118.5 119.5 120.5 121.5 122.5 123.5 124.5 125.5]

    I think the initial 0s are incorrect.

    Is this a bug or a new feature?

  • EMA always return 0.00

    EMA always return 0.00

    Hello, i used your code with data and ... nothing works. For example EMA always gives 0

    Volume:	870.19 Time:	2021-11-28T07:00:00 -> 2021-11-28T08:00:00
    Open:	54377.42
    Close:	54475.96
    High:	54590.48
    Low:	54173.81
    Volume:	787.07 Time:	2021-11-28T08:00:00 -> 2021-11-28T09:00:00
    Open:	54475.97
    Close:	54515.61
    High:	54636.65
    Low:	54396.33
    Volume:	985.20 Time:	2021-11-28T09:00:00 -> 2021-11-28T10:00:00
    Open:	54515.60
    Close:	54396.20
    High:	54682.90
    Low:	54231.92
    Volume:	823.84 Time:	2021-11-28T10:00:00 -> 2021-11-28T11:00:00
    Open:	54393.87
    Close:	54335.80
    High:	54475.00
    Low:	54130.72
    Volume:	765.69 Time:	2021-11-28T11:00:00 -> 2021-11-28T12:00:00
    Open:	54335.80
    Close:	54718.15
    High:	54933.80
    Low:	54184.60
    Volume:	1028.53 Time:	2021-11-28T12:00:00 -> 2021-11-28T13:00:00
    Open:	54718.15
    Close:	54493.09
    High:	54875.00
    Low:	54425.27
    Volume:	1030.39 Time:	2021-11-28T13:00:00 -> 2021-11-28T14:00:00
    Open:	54493.10
    Close:	54356.62
    High:	54635.52
    Low:	54263.16
    Volume:	909.93 Time:	2021-11-28T14:00:00 -> 2021-11-28T15:00:00
    Open:	54356.62
    Close:	54274.20
    High:	54396.33
    Low:	54203.13
    Volume:	777.66 Time:	2021-11-28T15:00:00 -> 2021-11-28T16:00:00
    Open:	54274.20
    Close:	54365.00
    High:	54555.00
    Low:	54029.99
    Volume:	1130.34 Time:	2021-11-28T16:00:00 -> 2021-11-28T17:00:00
    Open:	54365.00
    Close:	54296.14
    High:	54450.00
    Low:	54169.84
    Volume:	753.77 Time:	2021-11-28T17:00:00 -> 2021-11-28T18:00:00
    Open:	54296.14
    Close:	54188.43
    High:	54373.00
    Low:	53942.01
    Volume:	1277.10 Time:	2021-11-28T18:00:00 -> 2021-11-28T19:00:00
    Open:	54188.43
    Close:	53896.37
    High:	54287.25
    Low:	53800.00
    Volume:	1358.34 Time:	2021-11-28T19:00:00 -> 2021-11-28T20:00:00
    Open:	53896.36
    Close:	54108.99
    High:	54186.17
    Low:	53256.64
    Volume:	2958.13 Time:	2021-11-28T20:00:00 -> 2021-11-28T21:00:00
    Open:	54108.99
    Close:	54617.85
    High:	54967.50
    Low:	54044.98
    Volume:	2249.23 Time:	2021-11-28T21:00:00 -> 2021-11-28T22:00:00
    Open:	54617.85
    Close:	54918.51
    High:	55149.99
    Low:	54617.84
    Volume:	1304.77 Time:	2021-11-28T22:00:00 -> 2021-11-28T23:00:00
    Open:	54918.51
    Close:	56273.23
    High:	56390.00
    Low:	54863.01
    Volume:	3117.97 Time:	2021-11-28T23:00:00 -> 2021-11-29T00:00:00
    Open:	56273.23
    Close:	56029.82
    High:	56729.72
    Low:	56023.01
    Volume:	2427.77 Time:	2021-11-29T00:00:00 -> 2021-11-29T01:00:00
    Open:	56029.81
    Close:	57274.88
    High:	57445.05
    Low:	56000.00
    Volume:	3468.79 Time:	2021-11-29T01:00:00 -> 2021-11-29T02:00:00
    Open:	57274.89
    Close:	57765.73
    High:	58000.15
    Low:	57136.56
    Volume:	3073.53 Time:	2021-11-29T02:00:00 -> 2021-11-29T03:00:00
    Open:	57765.73
    Close:	57639.76
    High:	58242.09
    Low:	57501.99
    Volume:	2729.83 Time:	2021-11-29T03:00:00 -> 2021-11-29T04:00:00
    Open:	57643.14
    Close:	57309.25
    High:	57715.42
    Low:	57269.72
    Volume:	1769.15 Time:	2021-11-29T04:00:00 -> 2021-11-29T05:00:00
    Open:	57309.26
    Close:	57359.02
    High:	57426.95
    Low:	57176.00
    Volume:	1648.18 Time:	2021-11-29T05:00:00 -> 2021-11-29T06:00:00
    Open:	57359.02
    Close:	57249.58
    High:	57642.93
    Low:	57232.00
    Volume:	1358.98 Time:	2021-11-29T06:00:00 -> 2021-11-29T07:00:00
    Open:	57249.58
    Close:	57325.75
    High:	57384.99
    Low:	57200.00
    Volume:	801.75 Time:	2021-11-29T07:00:00 -> 2021-11-29T08:00:00
    Open:	57325.76
    Close:	57426.91
    High:	57500.63
    Low:	57309.65
    Volume:	1002.85 Time:	2021-11-29T08:00:00 -> 2021-11-29T09:00:00
    Open:	57426.92
    Close:	57515.13
    High:	57688.00
    Low:	57390.00
    Volume:	1047.27 Time:	2021-11-29T09:00:00 -> 2021-11-29T10:00:00
    Open:	57512.17
    Close:	57514.33
    High:	57642.85
    Low:	57455.08
    Volume:	174.91]}
    
    EMA output: 0.00
    

    The code :

    df := techan.NewTimeSeries()
    
    	for _, k := range *klines {
    		// opentime, open, high, low, close, volume
    		period := techan.NewTimePeriod(time.Unix(k.OpenTime/1000, 0), *duration)
    
    		candle := techan.NewCandle(period)
    		candle.OpenPrice = big.NewFromString(k.Open)
    		candle.ClosePrice = big.NewFromString(k.Close)
    		candle.MaxPrice = big.NewFromString(k.High)
    		candle.MinPrice = big.NewFromString(k.Low)
    		candle.Volume = big.NewFromString(k.Volume)
    
    		df.AddCandle(candle)
    	}
    
    	fmt.Println(df)
            closePrices := techan.NewClosePriceIndicator(df)
    	movingAverage := techan.NewEMAIndicator(closePrices, 10) // Create an exponential moving average with a window of 10
    
    	fmt.Println("EMA output :" + movingAverage.Calculate(0).FormattedString(2))
    
  • Requesting improved documentation by examples and more detailed comments

    Requesting improved documentation by examples and more detailed comments

    Am very appreciative of you work on this. Please add more documentation via examples, with comments on every line, and more realistic scenarios. I know this seems like just a chore, and it’s easier said than done, but needs to be done. For example, examples were last updated 4 years ago, but last update seems to have been 26 days ago, to the Readme. I have to fight for better documentation at work every day :) Always tough to justify the time spent on it. But I find that, as a result, people tend to get a more solid start, ask fewer “dumb” questions along the way, use the code in the right way, figure out issues more efficiently on their own, and they are more willing to contribute in kind when they resolve the eventual bug. Thank you

  • add price volume trend indicator

    add price volume trend indicator

    Reference: https://www.investopedia.com/terms/v/vptindicator.asp

    Formula Used:

    1. For second candle: [((CurrentClose - PreviousClose) / PreviousClose) x Volume] + 0 (because there is no PVT to first candle)

    2. For subsequent candles: [((CurrentClose - PreviousClose) / PreviousClose) x Volume] + PreviousPVT

    Usage:

    	closePrices := techan.NewClosePriceIndicator(series)
    	volume := techan.NewVolumeIndicator(series)
    
    	pvtIndicator := techan.NewPriceVolumeTrendIndicator(closePrices, volume, 1)
    	fmt.Println("PVT - ", pvtIndicator.Calculate(n)
    
    	pvtSignalIndicator := techan.NewPVTAndSignalIndicator(pvtIndicator, techan.NewEMAIndicator(pvtIndicator, 21))
    	fmt.Println("PVT - Signal - ", pvtSignalIndicator.Calculate(n)
    
    

    Where n is the index. It should be size of the series.

    Signed-off-by: Santosh Pillai [email protected]

  • [Feature] Support/Resistance levels indicator

    [Feature] Support/Resistance levels indicator

    Hi! Thanks for your library! I think it would be useful to add support and resistance levels indicator for a symbol. https://www.investopedia.com/trading/support-and-resistance-basics/

Go library containing a collection of financial functions for time value of money (annuities), cash flow, interest rate conversions, bonds and depreciation calculations.

go-finance Go library containing a collection of financial functions for time value of money (annuities), cash flow, interest rate conversions, bonds

Jan 2, 2023
Payment abstraction library - one interface for multiple payment processors ( inspired by Ruby's ActiveMerchant )

Sleet Payment abstraction library - interact with different Payment Service Providers (PsP) with one unified interface. Installation go get github.com

Dec 28, 2022
money and currency formatting for golang

accounting - money and currency formatting for golang accounting is a library for money and currency formatting. (inspired by accounting.js) Quick Sta

Dec 21, 2022
Matching Engine for Limit Order Book in Golang

Go orderbook Improved matching engine written in Go (Golang) Features Standard price-time priority Supports both market and limit orders Supports orde

Dec 22, 2022
Package to easily consume the Dolarpy API in golang.

dolarpy-go Package to easily consume the Dolarpy API in golang. https://github.com/melizeche/dolarPy - by melizeche Install import "github.com/bitebai

Apr 11, 2022
Go-finproto - a collection of finance-related protocols implemented in Golang

go-finproto go-finproto is a collection of finance-related protocols implemented

Dec 25, 2022
Entain BE Technical Test with golang
Entain BE Technical Test with golang

Entain BE Technical Test This test has been designed to demonstrate your ability and understanding of technologies commonly used at Entain. Please tre

Nov 17, 2021
MNC Technical Test With Golang

MNC Technical Test With Golang

Nov 20, 2021
Collection of Technical Interview Questions solved with Go

go-interview Collection of Technical Interview Questions solved with Go Algorithms A Star Datastructures Linked Lists Doubly Linked List Singly Linked

Jan 9, 2023
Developed Code for the Fulfillment of the technical task given by Appointy using Go

INSTAGRAM BACKEND API BY KUNAL KULKARNI Table of Contents About The Project Built With Getting Started Prerequisites Installation Usage License Contac

Oct 10, 2021
Manage internal technical documentation that is enriched with live data accreted from your environment.

Manage internal technical documentation that is enriched with live data accreted from your environment.

Jan 3, 2023
World Trade Technical Chain

World Trade Technical Chain Introduction to WTT Chain World Trade Technical Chain (WTT) is a decentralized, high-efficiency and energy-saving public c

Dec 4, 2021
Technical specifications for the IPFS protocol stack
Technical specifications for the IPFS protocol stack

IPFS Specifications This repository contains the specs for the IPFS Protocol and associated subsystems. Understanding the meaning of the spec badges a

Jan 7, 2023
Web terminal - A (unsafe) technical demo to export a shell to web browser
Web terminal - A (unsafe) technical demo to export a shell to web browser

Web Terminal A (unsafe) technical demo to export a shell to web browser. This pr

Dec 27, 2022
Implementation of Technical Test - Article API
Implementation of Technical Test - Article API

Technical Test on Article API Abstract For the technical test on an set of article API, this document outlines its requirements, and the design, devel

Feb 8, 2022
Entain - Entain BE Technical Test
Entain - Entain BE Technical Test

Entain BE Technical Test This test has been designed to demonstrate your ability

Feb 3, 2022
A web based technical SEO audit tool.
A web based technical SEO audit tool.

SEOnaut This repository contains the code for SEOnaut, a web based technical SEO audit tool. A hosted version of SEOnaut is available at seonaut.org.

Dec 22, 2022
Selected Machine Learning algorithms for natural language processing and semantic analysis in Golang

Natural Language Processing Implementations of selected machine learning algorithms for natural language processing in golang. The primary focus for t

Dec 25, 2022