Technical Analysis Library for Golang

Overview

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.

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.

    opened by 0cv 4
  • 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
                                     }
    
    opened by joelnordell 3
  • 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?

    opened by zhengyangfeng00 3
  • 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?

    opened by SunRunAwayAwayAway 2
  • 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?

    opened by Gauthamastro 2
  • 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?

    opened by helloworldpark 2
  • 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?

    opened by beaquant 2
  • 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.

    opened by beaquant 2
  • 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/

    opened by MarErm27 1
  • 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 ?

    opened by jbrodriguez 1
  • 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 ..

    opened by danhenke 1
  • 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

    opened by konrin 1
  • 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?

    opened by shkim 0
  • 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))
    
    opened by Chipsterjulien 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

    opened by atljoseph 0
  • 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]

    opened by sp98 1
  • [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/

    opened by tarcomru 0
Releases(0.3.0)
Owner
Steve Coffey
Engineer by day, asleep by night
Steve Coffey
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

Alejandro Pedraza 142 Sep 19, 2022
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

Bolt 99 Sep 9, 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

Kyoung-chan Lee 765 Sep 13, 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

Karlson Lee 295 Sep 26, 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

bitebait 1 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

Mark Winter 7 Aug 29, 2022
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

null 0 Nov 17, 2021
MNC Technical Test With Golang

MNC Technical Test With Golang

Angga Suwito 0 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

Raed Shomali 3.9k Sep 25, 2022
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

Kunal Kulkarni 1 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.

Daniel Tedman 0 Dec 11, 2021
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

Gavin 1 Dec 4, 2021
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

IPFS 979 Sep 11, 2022
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

null 61 Aug 25, 2022
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

Spenser Kao 0 Feb 8, 2022
Entain - Entain BE Technical Test

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

Bogdan_Todor 0 Feb 3, 2022
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.

StJudeWasHere 14 Sep 11, 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

James Bowman 373 Sep 15, 2022