├── web
├── src
│ ├── assets
│ │ ├── .gitkeep
│ │ ├── page-logo.png
│ │ ├── background.jpg
│ │ └── early-dumb-donate.png
│ ├── app
│ │ ├── shared
│ │ │ ├── classes
│ │ │ │ ├── config.ts
│ │ │ │ └── wallet.ts
│ │ │ ├── orders
│ │ │ │ ├── orders.component.scss
│ │ │ │ ├── orders.component.html
│ │ │ │ ├── orders.component.ts
│ │ │ │ └── orders.component.spec.ts
│ │ │ ├── buy-sell
│ │ │ │ ├── buy-sell.component.scss
│ │ │ │ ├── buy-sell.component.html
│ │ │ │ ├── buy-sell.component.ts
│ │ │ │ └── buy-sell.component.spec.ts
│ │ │ ├── my-orders
│ │ │ │ ├── my-orders.component.scss
│ │ │ │ ├── my-orders.component.html
│ │ │ │ ├── my-orders.component.ts
│ │ │ │ └── my-orders.component.spec.ts
│ │ │ ├── buy-sell-form
│ │ │ │ ├── buy-sell-form.component.scss
│ │ │ │ ├── buy-sell-form.component.html
│ │ │ │ ├── buy-sell-form.component.ts
│ │ │ │ └── buy-sell-form.component.spec.ts
│ │ │ ├── price-history
│ │ │ │ ├── price-history.component.scss
│ │ │ │ ├── price-history.component.html
│ │ │ │ ├── price-history.component.ts
│ │ │ │ └── price-history.component.spec.ts
│ │ │ ├── trade-history
│ │ │ │ ├── trade-history.component.scss
│ │ │ │ ├── trade-history.component.html
│ │ │ │ ├── trade-history.component.ts
│ │ │ │ └── trade-history.component.spec.ts
│ │ │ ├── selected-currency
│ │ │ │ ├── selected-currency.component.scss
│ │ │ │ ├── selected-currency.component.ts
│ │ │ │ ├── selected-currency.component.html
│ │ │ │ └── selected-currency.component.spec.ts
│ │ │ ├── all-enabled-currency-tickers
│ │ │ │ ├── all-enabled-currency-tickers.component.scss
│ │ │ │ ├── all-enabled-currency-tickers.component.html
│ │ │ │ ├── all-enabled-currency-tickers.component.spec.ts
│ │ │ │ └── all-enabled-currency-tickers.component.ts
│ │ │ ├── navbar
│ │ │ │ ├── navbar.component.scss
│ │ │ │ ├── navbar.component.ts
│ │ │ │ ├── navbar.component.html
│ │ │ │ └── navbar.component.spec.ts
│ │ │ ├── exchange-currency-ticker
│ │ │ │ ├── exchange-currency-ticker.component.scss
│ │ │ │ ├── exchange-currency-ticker.component.spec.ts
│ │ │ │ ├── exchange-currency-ticker.component.ts
│ │ │ │ └── exchange-currency-ticker.component.html
│ │ │ └── theme-picker
│ │ │ │ ├── theme-picker.html
│ │ │ │ ├── theme-picker.spec.ts
│ │ │ │ ├── theme-picker.scss
│ │ │ │ └── theme-picker.ts
│ │ ├── pages
│ │ │ ├── about
│ │ │ │ ├── about.component.scss
│ │ │ │ ├── about.component.html
│ │ │ │ ├── about.component.ts
│ │ │ │ └── about.component.spec.ts
│ │ │ ├── history
│ │ │ │ ├── history.component.scss
│ │ │ │ ├── history.component.html
│ │ │ │ ├── history.component.ts
│ │ │ │ └── history.component.spec.ts
│ │ │ ├── exchange-grid
│ │ │ │ ├── exchange-grid.component.scss
│ │ │ │ ├── exchange-grid.component.ts
│ │ │ │ ├── exchange-grid.component.spec.ts
│ │ │ │ └── exchange-grid.component.html
│ │ │ ├── home
│ │ │ │ ├── home.component.scss
│ │ │ │ ├── home.component.html
│ │ │ │ ├── home.component.ts
│ │ │ │ └── home.component.spec.ts
│ │ │ ├── currency-list
│ │ │ │ ├── currency-list.component.scss
│ │ │ │ ├── currency-list.component.ts
│ │ │ │ ├── currency-list.component.spec.ts
│ │ │ │ └── currency-list.component.html
│ │ │ ├── trading
│ │ │ │ ├── trading.component.scss
│ │ │ │ ├── trading.component.html
│ │ │ │ ├── trading.component.ts
│ │ │ │ └── trading.component.spec.ts
│ │ │ ├── settings
│ │ │ │ ├── settings.component.scss
│ │ │ │ └── settings.component.spec.ts
│ │ │ ├── wallet
│ │ │ │ ├── wallet.component.scss
│ │ │ │ ├── wallet.component.spec.ts
│ │ │ │ └── wallet.component.ts
│ │ │ ├── donate
│ │ │ │ ├── donate.component.scss
│ │ │ │ ├── donate.component.ts
│ │ │ │ ├── donate.component.html
│ │ │ │ └── donate.component.spec.ts
│ │ │ └── dashboard
│ │ │ │ ├── dashboard.component.scss
│ │ │ │ ├── dashboard.component.spec.ts
│ │ │ │ ├── dashboard.component.html
│ │ │ │ └── dashboard.component.ts
│ │ ├── services
│ │ │ ├── sidebar
│ │ │ │ ├── sidebar.service.spec.ts
│ │ │ │ └── sidebar.service.ts
│ │ │ ├── websocket
│ │ │ │ ├── websocket.service.spec.ts
│ │ │ │ └── websocket.service.ts
│ │ │ ├── websocket-handler
│ │ │ │ ├── websocket-handler.service.spec.ts
│ │ │ │ └── websocket-handler.service.ts
│ │ │ ├── theme-storage
│ │ │ │ ├── theme-storage.service.ts
│ │ │ │ └── theme-storage.service.spec.ts
│ │ │ └── style-manager
│ │ │ │ ├── style-manager.service.ts
│ │ │ │ └── style-manager.service.spec.ts
│ │ ├── app.component.spec.ts
│ │ ├── providers
│ │ │ └── electron.service.ts
│ │ ├── app.component.scss
│ │ ├── app.component.ts
│ │ ├── app-routing.module.ts
│ │ └── app.component.html
│ ├── favicon.ico
│ ├── typings.d.ts
│ ├── environments
│ │ ├── index.prod.ts
│ │ └── index.ts
│ ├── tsconfig.app.json
│ ├── main.ts
│ ├── tsconfig.spec.json
│ ├── index.html
│ ├── test.ts
│ ├── styles.scss
│ └── polyfills.ts
├── _config.yml
├── logo-angular.jpg
├── logo-electron.jpg
├── .travis.yml
├── e2e
│ ├── app.po.ts
│ ├── tsconfig.e2e.json
│ └── app.e2e-spec.ts
├── .editorconfig
├── tsconfig.json
├── .gitignore
├── protractor.conf.js
├── .angular-cli.json
├── karma.conf.js
├── package.js
├── main.ts
├── README.md
└── tslint.json
├── Dockerfile
├── tools
├── portfolio
│ └── portfolio_test.go
└── config
│ ├── config_test.go
│ └── config.go
├── .gitignore
├── CONTRIBUTORS
├── docker-compose.yml
├── .travis.yml
├── testdata
└── test.sh
├── main_test.go
├── currency
├── symbol
│ ├── symbol_test.go
│ └── symbol.go
└── translation
│ ├── translation.go
│ └── translation_test.go
├── exchanges
├── huobi
│ ├── huobi_types.go
│ ├── huobi_test.go
│ └── huobi_wrapper.go
├── coinut
│ ├── coinut_test.go
│ └── coinut_websocket.go
├── okcoin
│ └── okcoin_test.go
├── bitfinex
│ ├── bitfinex_wrapper_test.go
│ └── bitfinex_websocket_test.go
├── alphapoint
│ ├── alphapoint_websocket.go
│ └── alphapoint_wrapper.go
├── localbitcoins
│ ├── localbitcoins_test.go
│ └── localbitcoins_wrapper.go
├── nonce
│ ├── nonce.go
│ └── nonce_test.go
├── poloniex
│ └── poloniex_test.go
├── bitstamp
│ └── bitstamp_websocket.go
├── btcc
│ ├── btcc_test.go
│ ├── btcc_websocket.go
│ └── btcc_wrapper.go
├── anx
│ ├── anx_types.go
│ └── anx_wrapper.go
├── kraken
│ └── kraken_types.go
├── lakebtc
│ ├── lakebtc_test.go
│ └── lakebtc_types.go
├── liqui
│ ├── liqui_test.go
│ └── liqui_types.go
├── gdax
│ └── gdax_websocket.go
├── wex
│ └── wex_test.go
├── itbit
│ ├── itbit_wrapper.go
│ └── itbit_test.go
└── btcmarkets
│ └── btcmarkets_test.go
├── doc
└── coding_style.md
├── orders_test.go
├── LICENSE
├── orders.go
├── config
├── config_encryption_test.go
└── config_encryption.go
└── restful_router.go
/web/src/assets/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/web/src/app/shared/classes/config.ts:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/web/_config.yml:
--------------------------------------------------------------------------------
1 | theme: jekyll-theme-architect
--------------------------------------------------------------------------------
/web/src/app/pages/about/about.component.scss:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/web/src/app/pages/history/history.component.scss:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/web/src/app/shared/orders/orders.component.scss:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/web/src/app/shared/buy-sell/buy-sell.component.scss:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/web/src/app/shared/my-orders/my-orders.component.scss:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/web/src/app/pages/exchange-grid/exchange-grid.component.scss:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/web/src/app/shared/buy-sell-form/buy-sell-form.component.scss:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/web/src/app/shared/price-history/price-history.component.scss:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/web/src/app/shared/trade-history/trade-history.component.scss:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/web/src/app/shared/selected-currency/selected-currency.component.scss:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM golang:onbuild
2 | COPY config_example.dat config.dat
3 |
4 |
--------------------------------------------------------------------------------
/web/src/app/pages/about/about.component.html:
--------------------------------------------------------------------------------
1 |
2 | about works!
3 |
4 |
--------------------------------------------------------------------------------
/web/src/app/pages/history/history.component.html:
--------------------------------------------------------------------------------
1 |
2 | history works!
3 |
4 |
--------------------------------------------------------------------------------
/web/src/app/pages/home/home.component.scss:
--------------------------------------------------------------------------------
1 | .example-card {
2 | width: 400px;
3 | }
--------------------------------------------------------------------------------
/web/src/app/shared/all-enabled-currency-tickers/all-enabled-currency-tickers.component.scss:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/web/logo-angular.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Dimillian/gocryptotrader/master/web/logo-angular.jpg
--------------------------------------------------------------------------------
/web/src/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Dimillian/gocryptotrader/master/web/src/favicon.ico
--------------------------------------------------------------------------------
/web/logo-electron.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Dimillian/gocryptotrader/master/web/logo-electron.jpg
--------------------------------------------------------------------------------
/web/src/app/shared/buy-sell-form/buy-sell-form.component.html:
--------------------------------------------------------------------------------
1 |
2 | buy-sell-form works!
3 |
4 |
--------------------------------------------------------------------------------
/web/src/assets/page-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Dimillian/gocryptotrader/master/web/src/assets/page-logo.png
--------------------------------------------------------------------------------
/web/src/assets/background.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Dimillian/gocryptotrader/master/web/src/assets/background.jpg
--------------------------------------------------------------------------------
/tools/portfolio/portfolio_test.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import "testing"
4 |
5 | func TestMain(t *testing.T) {
6 |
7 | }
8 |
--------------------------------------------------------------------------------
/web/src/assets/early-dumb-donate.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Dimillian/gocryptotrader/master/web/src/assets/early-dumb-donate.png
--------------------------------------------------------------------------------
/web/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - "7"
4 | - "6"
5 | install:
6 | - npm install
7 | script:
8 | - npm run build
9 |
--------------------------------------------------------------------------------
/web/src/app/shared/navbar/navbar.component.scss:
--------------------------------------------------------------------------------
1 | .material-icons {
2 | cursor: pointer;
3 | }
4 |
5 | .flex-spacer {
6 | flex-grow: 1;
7 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | config.json
2 | config.dat
3 | node_modules
4 | lib
5 | .vscode
6 |
7 | testdata/dump
8 | testdata/writefiletest
9 |
10 | # InteliJ
11 | .idea
12 | *.iml
13 |
--------------------------------------------------------------------------------
/web/src/app/pages/currency-list/currency-list.component.scss:
--------------------------------------------------------------------------------
1 | .BTC {
2 | color:orange;
3 | }
4 | .LTC {
5 | color:silver;
6 | }
7 | .ETH {
8 | color:darkslategrey;
9 | }
--------------------------------------------------------------------------------
/web/src/app/pages/trading/trading.component.scss:
--------------------------------------------------------------------------------
1 |
2 | .mat-fab {
3 | top: auto;
4 | right: 30px;
5 | bottom: 20px;
6 | left: auto;
7 | position: fixed;
8 | z-index: 3;
9 | }
--------------------------------------------------------------------------------
/web/src/app/shared/orders/orders.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Orders
4 |
5 |
--------------------------------------------------------------------------------
/web/src/app/pages/trading/trading.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/web/src/app/shared/my-orders/my-orders.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | My Orders
4 |
5 |
--------------------------------------------------------------------------------
/web/e2e/app.po.ts:
--------------------------------------------------------------------------------
1 | import { browser, element, by } from 'protractor';
2 |
3 | /* tslint:disable */
4 | export class AngularElectronPage {
5 | navigateTo(route: string) {
6 | return browser.get(route);
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/web/src/app/shared/price-history/price-history.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Price History
4 |
5 |
--------------------------------------------------------------------------------
/web/src/app/shared/trade-history/trade-history.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Trade History
4 |
5 |
--------------------------------------------------------------------------------
/web/src/app/pages/settings/settings.component.scss:
--------------------------------------------------------------------------------
1 | // FAB
2 | .mat-fab {
3 | top: auto;
4 | right: 30px;
5 | bottom: 20px;
6 | left: auto;
7 | position: fixed;
8 | }
9 |
10 | .form-content {
11 | margin: 20px;
12 | }
--------------------------------------------------------------------------------
/web/src/app/pages/wallet/wallet.component.scss:
--------------------------------------------------------------------------------
1 | .wallet-card {
2 | width: 80%;
3 | margin: 10px auto;
4 | }
5 |
6 | .BTC {
7 | color:orange;
8 | }
9 | .LTC {
10 | color:silver;
11 | }
12 | .ETH {
13 | color:darkslategrey;
14 | }
--------------------------------------------------------------------------------
/web/src/app/pages/donate/donate.component.scss:
--------------------------------------------------------------------------------
1 | .BTC {
2 | color:orange;
3 | }
4 |
5 | .full-card {
6 | width: 30%;
7 | margin: 0px auto !important;
8 | }
9 |
10 | .heart {
11 | margin: 0px auto !important;
12 | display:flex;
13 | }
--------------------------------------------------------------------------------
/web/src/typings.d.ts:
--------------------------------------------------------------------------------
1 | /* SystemJS module definition */
2 | declare var nodeModule: NodeModule;
3 | interface NodeModule {
4 | id: string;
5 | }
6 |
7 | declare var window: Window;
8 | interface Window {
9 | process: any;
10 | require: any;
11 | }
12 |
--------------------------------------------------------------------------------
/web/src/environments/index.prod.ts:
--------------------------------------------------------------------------------
1 | // This file contains production variables. (When you work in PROD MODE)
2 | // This file is use by webpack. Please don't rename it and don't move it to another directory.
3 | export const environment = {
4 | production: true
5 | };
6 |
--------------------------------------------------------------------------------
/web/src/environments/index.ts:
--------------------------------------------------------------------------------
1 | // This file contains development variables. (When you work in DEV MODE)
2 | // This file is use by webpack. Please don't rename it and don't move it to another directory.
3 | export const environment = {
4 | production: false
5 | };
6 |
--------------------------------------------------------------------------------
/web/e2e/tsconfig.e2e.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "../out-tsc/e2e",
5 | "module": "commonjs",
6 | "target": "es5",
7 | "types":[
8 | "jasmine",
9 | "node"
10 | ]
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/web/.editorconfig:
--------------------------------------------------------------------------------
1 | # Editor configuration, see http://editorconfig.org
2 | root = true
3 |
4 | [*]
5 | charset = utf-8
6 | indent_style = space
7 | indent_size = 2
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 |
11 | [*.md]
12 | max_line_length = off
13 | trim_trailing_whitespace = false
14 |
--------------------------------------------------------------------------------
/CONTRIBUTORS:
--------------------------------------------------------------------------------
1 | Thanks to the following contributors:
2 |
3 | Scott - gloriousCode
4 | Ryan O'Hara-Reid - shazbert
5 | Jacob Gadikian - faddat
6 | Cornel - cornelk
7 | Łukasz Kurowski - crackcomm
8 | Adrian Gallagher - thrasher-
9 | Manuel Kreutz - 140am
10 | libsora.so - if1live
11 | Tong - tongxiaofeng
12 | Jamie Cheng - starit
13 | Jake - snipesjr
--------------------------------------------------------------------------------
/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: '2'
2 | services:
3 | web:
4 | build: web/
5 | hostname: gocryptotraderweb
6 | container_name: web
7 | ports:
8 | - "3333:80"
9 | cli:
10 | build: .
11 | hostname: gocryptotrader
12 | container_name: daemon
13 | privileged: true
14 |
--------------------------------------------------------------------------------
/web/src/tsconfig.app.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "../out-tsc/app",
5 | "module": "es2015",
6 | "baseUrl": "",
7 | "types": []
8 | },
9 | "exclude": [
10 | "test.ts",
11 | "**/*.spec.ts",
12 | "dist",
13 | "app-builds",
14 | "node_modules"
15 | ]
16 | }
17 |
--------------------------------------------------------------------------------
/web/src/app/pages/about/about.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit } from '@angular/core';
2 |
3 | @Component({
4 | selector: 'app-about',
5 | templateUrl: './about.component.html',
6 | styleUrls: ['./about.component.scss']
7 | })
8 | export class AboutComponent implements OnInit {
9 |
10 | constructor() { }
11 |
12 | ngOnInit() {
13 | }
14 |
15 | }
16 |
--------------------------------------------------------------------------------
/web/src/app/pages/donate/donate.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit } from '@angular/core';
2 |
3 | @Component({
4 | selector: 'app-donate',
5 | templateUrl: './donate.component.html',
6 | styleUrls: ['./donate.component.scss']
7 | })
8 | export class DonateComponent implements OnInit {
9 |
10 | constructor() { }
11 |
12 | ngOnInit() {
13 | }
14 |
15 | }
16 |
--------------------------------------------------------------------------------
/web/src/app/shared/orders/orders.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit } from '@angular/core';
2 |
3 | @Component({
4 | selector: 'app-orders',
5 | templateUrl: './orders.component.html',
6 | styleUrls: ['./orders.component.scss']
7 | })
8 | export class OrdersComponent implements OnInit {
9 |
10 | constructor() { }
11 |
12 | ngOnInit() {
13 | }
14 |
15 | }
16 |
--------------------------------------------------------------------------------
/web/src/main.ts:
--------------------------------------------------------------------------------
1 | import { enableProdMode } from '@angular/core';
2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
3 |
4 | import { AppModule } from './app/app.module';
5 | import { environment } from 'environments';
6 |
7 | if (environment.production) {
8 | enableProdMode();
9 | }
10 |
11 | platformBrowserDynamic().bootstrapModule(AppModule);
12 |
--------------------------------------------------------------------------------
/web/src/app/pages/history/history.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit } from '@angular/core';
2 |
3 | @Component({
4 | selector: 'app-history',
5 | templateUrl: './history.component.html',
6 | styleUrls: ['./history.component.scss']
7 | })
8 | export class HistoryComponent implements OnInit {
9 |
10 | constructor() { }
11 |
12 | ngOnInit() {
13 | }
14 |
15 | }
16 |
--------------------------------------------------------------------------------
/web/src/app/pages/home/home.component.html:
--------------------------------------------------------------------------------
1 |
2 | Welcome to GoCryptoTrader
3 | GoCryptoTrader is a multi-currency, multi-exchange trader for cryptocurrencies
4 | It is under active development and you can see its development progress by clicking the trello button to the left
5 | If you like what you see, consider clicking the donation button to the left
--------------------------------------------------------------------------------
/web/src/app/pages/trading/trading.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit } from '@angular/core';
2 |
3 | @Component({
4 | selector: 'app-trading',
5 | templateUrl: './trading.component.html',
6 | styleUrls: ['./trading.component.scss']
7 | })
8 | export class TradingComponent implements OnInit {
9 |
10 | constructor() { }
11 |
12 | ngOnInit() {
13 | }
14 |
15 | }
16 |
--------------------------------------------------------------------------------
/web/src/app/shared/my-orders/my-orders.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit } from '@angular/core';
2 |
3 | @Component({
4 | selector: 'app-my-orders',
5 | templateUrl: './my-orders.component.html',
6 | styleUrls: ['./my-orders.component.scss']
7 | })
8 | export class MyOrdersComponent implements OnInit {
9 |
10 | constructor() { }
11 |
12 | ngOnInit() {
13 | }
14 |
15 | }
16 |
--------------------------------------------------------------------------------
/web/src/app/shared/buy-sell/buy-sell.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | BUY
5 |
6 |
7 |
8 |
9 |
10 | SELL
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/web/src/app/pages/home/home.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit } from '@angular/core';
2 |
3 | @Component({
4 | selector: 'app-home',
5 | templateUrl: './home.component.html',
6 | styleUrls: ['./home.component.scss'],
7 |
8 | })
9 | export class HomeComponent implements OnInit {
10 | title = `App works !`;
11 |
12 | constructor() { }
13 |
14 | ngOnInit() {
15 | }
16 |
17 | }
18 |
--------------------------------------------------------------------------------
/web/src/app/pages/currency-list/currency-list.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit } from '@angular/core';
2 |
3 | @Component({
4 | selector: 'app-currency-list',
5 | templateUrl: './currency-list.component.html',
6 | styleUrls: ['./currency-list.component.scss']
7 | })
8 | export class CurrencyListComponent implements OnInit {
9 |
10 | constructor() { }
11 |
12 | ngOnInit() {
13 | }
14 |
15 | }
16 |
--------------------------------------------------------------------------------
/web/src/app/pages/exchange-grid/exchange-grid.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit } from '@angular/core';
2 |
3 | @Component({
4 | selector: 'app-exchange-grid',
5 | templateUrl: './exchange-grid.component.html',
6 | styleUrls: ['./exchange-grid.component.scss']
7 | })
8 | export class ExchangeGridComponent implements OnInit {
9 |
10 | constructor() { }
11 |
12 | ngOnInit() {
13 | }
14 |
15 | }
16 |
--------------------------------------------------------------------------------
/web/src/app/shared/buy-sell-form/buy-sell-form.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit } from '@angular/core';
2 |
3 | @Component({
4 | selector: 'app-buy-sell-form',
5 | templateUrl: './buy-sell-form.component.html',
6 | styleUrls: ['./buy-sell-form.component.scss']
7 | })
8 | export class BuySellFormComponent implements OnInit {
9 |
10 | constructor() { }
11 |
12 | ngOnInit() {
13 | }
14 |
15 | }
16 |
--------------------------------------------------------------------------------
/web/src/app/shared/price-history/price-history.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit } from '@angular/core';
2 |
3 | @Component({
4 | selector: 'app-price-history',
5 | templateUrl: './price-history.component.html',
6 | styleUrls: ['./price-history.component.scss']
7 | })
8 | export class PriceHistoryComponent implements OnInit {
9 |
10 | constructor() { }
11 |
12 | ngOnInit() {
13 | }
14 |
15 | }
16 |
--------------------------------------------------------------------------------
/web/src/app/shared/trade-history/trade-history.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit } from '@angular/core';
2 |
3 | @Component({
4 | selector: 'app-trade-history',
5 | templateUrl: './trade-history.component.html',
6 | styleUrls: ['./trade-history.component.scss']
7 | })
8 | export class TradeHistoryComponent implements OnInit {
9 |
10 | constructor() { }
11 |
12 | ngOnInit() {
13 | }
14 |
15 | }
16 |
--------------------------------------------------------------------------------
/web/src/app/shared/selected-currency/selected-currency.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit } from '@angular/core';
2 |
3 | @Component({
4 | selector: 'app-selected-currency',
5 | templateUrl: './selected-currency.component.html',
6 | styleUrls: ['./selected-currency.component.scss']
7 | })
8 | export class SelectedCurrencyComponent implements OnInit {
9 |
10 | constructor() { }
11 |
12 | ngOnInit() {
13 | }
14 |
15 | }
16 |
--------------------------------------------------------------------------------
/web/src/app/shared/buy-sell/buy-sell.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit,Directive, ViewContainerRef } from '@angular/core';
2 |
3 | @Component({
4 | selector: 'app-buy-sell',
5 | templateUrl: './buy-sell.component.html',
6 | styleUrls: ['./buy-sell.component.scss']
7 | })
8 | export class BuySellComponent implements OnInit {
9 |
10 | constructor(public viewContainerRef: ViewContainerRef) { }
11 |
12 | ngOnInit() {
13 | }
14 |
15 | }
16 |
--------------------------------------------------------------------------------
/web/e2e/app.e2e-spec.ts:
--------------------------------------------------------------------------------
1 | import { AngularElectronPage } from './app.po';
2 | import { browser, element, by } from 'protractor';
3 |
4 | describe('angular-electron App', () => {
5 | let page: AngularElectronPage;
6 |
7 | beforeEach(() => {
8 | page = new AngularElectronPage();
9 | });
10 |
11 | it('should display message saying App works !', () => {
12 | expect(element(by.css('app-home h1')).getText()).toMatch('App works !');
13 | });
14 | });
15 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: go
2 |
3 | go:
4 | - 1.8.x
5 | #- master
6 |
7 | before_install:
8 | - go get -t -v ./...
9 |
10 | script:
11 | - ./testdata/test.sh
12 |
13 | install:
14 | - go get github.com/gorilla/websocket
15 | - go get github.com/toorop/go-pusher
16 | - go get github.com/thrasher-/socketio
17 | - go get github.com/beatgammit/turnpike
18 | - go get github.com/gorilla/mux
19 |
20 | after_success:
21 | - bash <(curl -s https://codecov.io/bash)
22 |
--------------------------------------------------------------------------------
/tools/config/config_test.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import "testing"
4 |
5 | func TestEncryptOrDecrypt(t *testing.T) {
6 | reValue := EncryptOrDecrypt(true)
7 | if reValue != "encrypted" {
8 | t.Error(
9 | "Test failed - Tools/Config/Config_test.go - EncryptOrDecrypt Error",
10 | )
11 | }
12 | reValue = EncryptOrDecrypt(false)
13 | if reValue != "decrypted" {
14 | t.Error(
15 | "Test failed - Tools/Config/Config_test.go - EncryptOrDecrypt Error",
16 | )
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/web/src/app/pages/dashboard/dashboard.component.scss:
--------------------------------------------------------------------------------
1 | .full-card {
2 | margin: 10px;
3 | width: 100%;
4 | }
5 |
6 | ::ng-deep mat-grid-tile.mat-grid-tile .mat-figure {
7 | align-items: initial;
8 | /*vertical alignment*/
9 | }
10 |
11 | .mat-card-footer {
12 | position: absolute;
13 | bottom: 24px;
14 | }
15 |
16 | .mat-fab {
17 | top: auto;
18 | right: 30px;
19 | bottom: 20px;
20 | left: auto;
21 | position: fixed;
22 | z-index: 3;
23 | }
24 |
--------------------------------------------------------------------------------
/web/src/app/services/sidebar/sidebar.service.spec.ts:
--------------------------------------------------------------------------------
1 | import { TestBed, inject } from '@angular/core/testing';
2 |
3 | import { SidebarService } from './sidebar.service';
4 |
5 | describe('SidebarService', () => {
6 | beforeEach(() => {
7 | TestBed.configureTestingModule({
8 | providers: [SidebarService]
9 | });
10 | });
11 |
12 | it('should be created', inject([SidebarService], (service: SidebarService) => {
13 | expect(service).toBeTruthy();
14 | }));
15 | });
16 |
--------------------------------------------------------------------------------
/web/src/app/shared/exchange-currency-ticker/exchange-currency-ticker.component.scss:
--------------------------------------------------------------------------------
1 | .one-time-animation {
2 | animation: one-time-animation 2s forwards 1;
3 | }
4 | @keyframes one-time-animation {
5 | from {
6 | background: green;
7 | }
8 | to {
9 | background: transparent;
10 | }
11 | }
12 |
13 | /* do the following changes */
14 |
15 | .selected {
16 | box-shadow: 0 0 10px green inset;
17 | transition: box-shadow 2s ease;
18 | }
19 |
--------------------------------------------------------------------------------
/web/src/app/shared/all-enabled-currency-tickers/all-enabled-currency-tickers.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/web/src/tsconfig.spec.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "../out-tsc/spec",
5 | "module": "commonjs",
6 | "target": "es5",
7 | "baseUrl": "",
8 | "types": [
9 | "jasmine",
10 | "node"
11 | ]
12 | },
13 | "files": [
14 | "test.ts"
15 | ],
16 | "include": [
17 | "**/*.spec.ts",
18 | "**/*.d.ts"
19 | ],
20 | "exclude": [
21 | "dist",
22 | "app-builds",
23 | "node_modules"
24 | ]
25 | }
26 |
--------------------------------------------------------------------------------
/web/src/app/services/websocket/websocket.service.spec.ts:
--------------------------------------------------------------------------------
1 | import { TestBed, inject } from '@angular/core/testing';
2 |
3 | import { WebsocketService } from './websocket.service';
4 |
5 | describe('WebsocketService', () => {
6 | beforeEach(() => {
7 | TestBed.configureTestingModule({
8 | providers: [WebsocketService]
9 | });
10 | });
11 |
12 | it('should be created', inject([WebsocketService], (service: WebsocketService) => {
13 | expect(service).toBeTruthy();
14 | }));
15 | });
16 |
--------------------------------------------------------------------------------
/web/src/app/shared/selected-currency/selected-currency.component.html:
--------------------------------------------------------------------------------
1 |
2 |
7 |
--------------------------------------------------------------------------------
/testdata/test.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | set -e
4 |
5 | if [ -n "$TRAVIS_BUILD_DIR" ]; then
6 | cd $TRAVIS_BUILD_DIR
7 | else
8 | cd $GOPATH/src/github.com/thrasher-/gocryptotrader
9 | fi
10 |
11 | echo "" > testdata/coverage.txt
12 |
13 | for d in $(go list ./... | grep -v vendor); do
14 | go test -race -coverprofile=profile.out -covermode=atomic -cover $d
15 | if [ -f profile.out ]; then
16 | cat profile.out >> testdata/coverage.txt
17 | rm profile.out
18 | fi
19 | done
20 |
--------------------------------------------------------------------------------
/web/src/app/shared/classes/wallet.ts:
--------------------------------------------------------------------------------
1 |
2 | export interface CoinTotal {
3 | coin: string;
4 | balance: number;
5 | percentage: number;
6 | address: string;
7 | icon:string;
8 | }
9 |
10 | export interface Summary {
11 | BTC: CoinTotal[];
12 | ETH: CoinTotal[];
13 | LTC: CoinTotal[];
14 | }
15 |
16 | export interface Wallet {
17 | coin_totals: CoinTotal[];
18 | coins_offline: CoinTotal[];
19 | offline_summary: Summary;
20 | coins_online: CoinTotal[];
21 | online_summary: Summary;
22 | }
--------------------------------------------------------------------------------
/web/src/app/shared/navbar/navbar.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit } from '@angular/core';
2 | import { SidebarService } from './../../services/sidebar/sidebar.service';
3 |
4 | @Component({
5 | selector: 'app-navbar',
6 | templateUrl: './navbar.component.html',
7 | styleUrls: ['./navbar.component.scss']
8 | })
9 | export class NavbarComponent implements OnInit {
10 | sidebarService: SidebarService
11 | constructor(something: SidebarService) {
12 | this.sidebarService = something;
13 | }
14 |
15 | ngOnInit() {
16 | }
17 |
18 | }
19 |
--------------------------------------------------------------------------------
/web/src/app/services/websocket-handler/websocket-handler.service.spec.ts:
--------------------------------------------------------------------------------
1 | import { TestBed, inject } from '@angular/core/testing';
2 |
3 | import { WebsocketHandlerService } from './websocket-handler.service';
4 |
5 | describe('WebsocketHandlerService', () => {
6 | beforeEach(() => {
7 | TestBed.configureTestingModule({
8 | providers: [WebsocketHandlerService]
9 | });
10 | });
11 |
12 | it('should be created', inject([WebsocketHandlerService], (service: WebsocketHandlerService) => {
13 | expect(service).toBeTruthy();
14 | }));
15 | });
16 |
--------------------------------------------------------------------------------
/main_test.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import "testing"
4 |
5 | func TestSetupBotExchanges(t *testing.T) {
6 | // setupBotExchanges()
7 | }
8 |
9 | func TestMain(t *testing.T) {
10 | // Nothing
11 | }
12 |
13 | func TestAdjustGoMaxProcs(t *testing.T) {
14 | AdjustGoMaxProcs()
15 | }
16 |
17 | func TestHandleInterrupt(t *testing.T) {
18 | HandleInterrupt()
19 | }
20 |
21 | func TestShutdown(t *testing.T) {
22 | // Nothing
23 | }
24 |
25 | func TestSeedExchangeAccountInfo(t *testing.T) {
26 | SeedExchangeAccountInfo(GetAllEnabledExchangeAccountInfo().Data)
27 | }
28 |
--------------------------------------------------------------------------------
/currency/symbol/symbol_test.go:
--------------------------------------------------------------------------------
1 | package symbol
2 |
3 | import "testing"
4 |
5 | func TestGetSymbolByCurrencyName(t *testing.T) {
6 | expected := "₩"
7 | actual, err := GetSymbolByCurrencyName("KPW")
8 | if err != nil {
9 | t.Errorf("Test failed. TestGetSymbolByCurrencyName error: %s", err)
10 | }
11 |
12 | if actual != expected {
13 | t.Errorf("Test failed. TestGetSymbolByCurrencyName differing values")
14 | }
15 |
16 | _, err = GetSymbolByCurrencyName("BLAH")
17 | if err == nil {
18 | t.Errorf("Test failed. TestGetSymbolByCurrencyNam returned nil on non-existent currency")
19 | }
20 |
21 | }
22 |
--------------------------------------------------------------------------------
/exchanges/huobi/huobi_types.go:
--------------------------------------------------------------------------------
1 | package huobi
2 |
3 | // Ticker holds ticker information
4 | type Ticker struct {
5 | High float64
6 | Low float64
7 | Last float64
8 | Vol float64
9 | Buy float64
10 | Sell float64
11 | }
12 |
13 | // TickerResponse holds the initial response type
14 | type TickerResponse struct {
15 | Time string
16 | Ticker Ticker
17 | }
18 |
19 | // Orderbook holds the order book information
20 | type Orderbook struct {
21 | ID float64
22 | TS float64
23 | Bids [][]float64 `json:"bids"`
24 | Asks [][]float64 `json:"asks"`
25 | Symbol string `json:"string"`
26 | }
27 |
--------------------------------------------------------------------------------
/web/src/app/shared/navbar/navbar.component.html:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/web/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compileOnSave": false,
3 | "compilerOptions": {
4 | "module":"system",
5 | "outDir": "./dist/out-tsc",
6 | "baseUrl": "src",
7 | "sourceMap": true,
8 | "declaration": false,
9 | "moduleResolution": "node",
10 | "emitDecoratorMetadata": true,
11 | "experimentalDecorators": true,
12 | "allowJs": false,
13 | "target": "es5",
14 | "paths": {
15 | "environments": [
16 | "./environments"
17 | ]
18 | },
19 | "types": [
20 | "node",
21 | "jasmine"
22 | ],
23 | "typeRoots": [
24 | "node_modules/@types"
25 | ],
26 | "lib": [
27 | "es2016",
28 | "dom"
29 | ]
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/web/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | GoCryptoTrader
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/web/.gitignore:
--------------------------------------------------------------------------------
1 | # See http://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # compiled output
4 | /dist
5 | /tmp
6 | /out-tsc
7 | /app-builds
8 |
9 | # dependencies
10 | /node_modules
11 |
12 | # IDEs and editors
13 | /.idea
14 | .project
15 | .classpath
16 | .c9/
17 | *.launch
18 | .settings/
19 | *.sublime-workspace
20 |
21 | # IDE - VSCode
22 | .vscode/*
23 | !.vscode/settings.json
24 | !.vscode/tasks.json
25 | !.vscode/launch.json
26 | !.vscode/extensions.json
27 |
28 | # misc
29 | /.sass-cache
30 | /connect.lock
31 | /coverage
32 | /libpeerconnection.log
33 | npm-debug.log
34 | testem.log
35 | /typings
36 |
37 | # e2e
38 | /e2e/*.js
39 | /e2e/*.map
40 |
41 | # System Files
42 | .DS_Store
43 | Thumbs.db
44 |
--------------------------------------------------------------------------------
/exchanges/coinut/coinut_test.go:
--------------------------------------------------------------------------------
1 | package coinut
2 |
3 | //
4 | // const (
5 | // apiKey = ""
6 | // apiSecret = ""
7 | // )
8 | //
9 | // var c COINUT
10 | //
11 | // func TestSetDefaults(t *testing.T) {
12 | // c.SetDefaults()
13 | // }
14 | //
15 | // func TestSetup(t *testing.T) {
16 | // exch := config.ExchangeConfig{}
17 | // c.Setup(exch)
18 | //
19 | // exch.Enabled = true
20 | // exch.APIKey = apiKey
21 | // exch.APISecret = apiSecret
22 | // c.Setup(exch)
23 | // }
24 | //
25 | // // func TestGetInstruments(t *testing.T) {
26 | // // c.Verbose = true
27 | // // resp, err := c.GetInstruments()
28 | // // if err == nil {
29 | // // t.Error("Test failed - GetInstruments() error", err)
30 | // // }
31 | // // log.Println(resp)
32 | // // }
33 |
--------------------------------------------------------------------------------
/web/src/app/pages/about/about.component.spec.ts:
--------------------------------------------------------------------------------
1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing';
2 |
3 | import { AboutComponent } from './about.component';
4 |
5 | describe('AboutComponent', () => {
6 | let component: AboutComponent;
7 | let fixture: ComponentFixture;
8 |
9 | beforeEach(async(() => {
10 | TestBed.configureTestingModule({
11 | declarations: [ AboutComponent ]
12 | })
13 | .compileComponents();
14 | }));
15 |
16 | beforeEach(() => {
17 | fixture = TestBed.createComponent(AboutComponent);
18 | component = fixture.componentInstance;
19 | fixture.detectChanges();
20 | });
21 |
22 | it('should be created', () => {
23 | expect(component).toBeTruthy();
24 | });
25 | });
26 |
--------------------------------------------------------------------------------
/web/src/app/pages/donate/donate.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Donations
4 | We give our thanks
5 |
6 |
7 |
8 | If this framework helped you in any way, or you would like to support the developers working on it, please donate
9 |
10 |
11 | attach_money
12 | Address:
13 | 1F5zVDgNjorJ51oGebSvNCrSAHpwGkUdDB
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/web/src/app/pages/donate/donate.component.spec.ts:
--------------------------------------------------------------------------------
1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing';
2 |
3 | import { DonateComponent } from './donate.component';
4 |
5 | describe('DonateComponent', () => {
6 | let component: DonateComponent;
7 | let fixture: ComponentFixture;
8 |
9 | beforeEach(async(() => {
10 | TestBed.configureTestingModule({
11 | declarations: [ DonateComponent ]
12 | })
13 | .compileComponents();
14 | }));
15 |
16 | beforeEach(() => {
17 | fixture = TestBed.createComponent(DonateComponent);
18 | component = fixture.componentInstance;
19 | fixture.detectChanges();
20 | });
21 |
22 | it('should create', () => {
23 | expect(component).toBeTruthy();
24 | });
25 | });
26 |
--------------------------------------------------------------------------------
/web/src/app/pages/wallet/wallet.component.spec.ts:
--------------------------------------------------------------------------------
1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing';
2 |
3 | import { WalletComponent } from './wallet.component';
4 |
5 | describe('WalletComponent', () => {
6 | let component: WalletComponent;
7 | let fixture: ComponentFixture;
8 |
9 | beforeEach(async(() => {
10 | TestBed.configureTestingModule({
11 | declarations: [ WalletComponent ]
12 | })
13 | .compileComponents();
14 | }));
15 |
16 | beforeEach(() => {
17 | fixture = TestBed.createComponent(WalletComponent);
18 | component = fixture.componentInstance;
19 | fixture.detectChanges();
20 | });
21 |
22 | it('should be created', () => {
23 | expect(component).toBeTruthy();
24 | });
25 | });
26 |
--------------------------------------------------------------------------------
/web/src/app/shared/navbar/navbar.component.spec.ts:
--------------------------------------------------------------------------------
1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing';
2 |
3 | import { NavbarComponent } from './navbar.component';
4 |
5 | describe('NavbarComponent', () => {
6 | let component: NavbarComponent;
7 | let fixture: ComponentFixture;
8 |
9 | beforeEach(async(() => {
10 | TestBed.configureTestingModule({
11 | declarations: [ NavbarComponent ]
12 | })
13 | .compileComponents();
14 | }));
15 |
16 | beforeEach(() => {
17 | fixture = TestBed.createComponent(NavbarComponent);
18 | component = fixture.componentInstance;
19 | fixture.detectChanges();
20 | });
21 |
22 | it('should be created', () => {
23 | expect(component).toBeTruthy();
24 | });
25 | });
26 |
--------------------------------------------------------------------------------
/web/src/app/shared/orders/orders.component.spec.ts:
--------------------------------------------------------------------------------
1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing';
2 |
3 | import { OrdersComponent } from './orders.component';
4 |
5 | describe('OrdersComponent', () => {
6 | let component: OrdersComponent;
7 | let fixture: ComponentFixture;
8 |
9 | beforeEach(async(() => {
10 | TestBed.configureTestingModule({
11 | declarations: [ OrdersComponent ]
12 | })
13 | .compileComponents();
14 | }));
15 |
16 | beforeEach(() => {
17 | fixture = TestBed.createComponent(OrdersComponent);
18 | component = fixture.componentInstance;
19 | fixture.detectChanges();
20 | });
21 |
22 | it('should create', () => {
23 | expect(component).toBeTruthy();
24 | });
25 | });
26 |
--------------------------------------------------------------------------------
/web/src/app/pages/history/history.component.spec.ts:
--------------------------------------------------------------------------------
1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing';
2 |
3 | import { HistoryComponent } from './history.component';
4 |
5 | describe('HistoryComponent', () => {
6 | let component: HistoryComponent;
7 | let fixture: ComponentFixture;
8 |
9 | beforeEach(async(() => {
10 | TestBed.configureTestingModule({
11 | declarations: [ HistoryComponent ]
12 | })
13 | .compileComponents();
14 | }));
15 |
16 | beforeEach(() => {
17 | fixture = TestBed.createComponent(HistoryComponent);
18 | component = fixture.componentInstance;
19 | fixture.detectChanges();
20 | });
21 |
22 | it('should create', () => {
23 | expect(component).toBeTruthy();
24 | });
25 | });
26 |
--------------------------------------------------------------------------------
/web/src/app/pages/trading/trading.component.spec.ts:
--------------------------------------------------------------------------------
1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing';
2 |
3 | import { TradingComponent } from './trading.component';
4 |
5 | describe('TradingComponent', () => {
6 | let component: TradingComponent;
7 | let fixture: ComponentFixture;
8 |
9 | beforeEach(async(() => {
10 | TestBed.configureTestingModule({
11 | declarations: [ TradingComponent ]
12 | })
13 | .compileComponents();
14 | }));
15 |
16 | beforeEach(() => {
17 | fixture = TestBed.createComponent(TradingComponent);
18 | component = fixture.componentInstance;
19 | fixture.detectChanges();
20 | });
21 |
22 | it('should create', () => {
23 | expect(component).toBeTruthy();
24 | });
25 | });
26 |
--------------------------------------------------------------------------------
/web/src/app/shared/buy-sell/buy-sell.component.spec.ts:
--------------------------------------------------------------------------------
1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing';
2 |
3 | import { BuySellComponent } from './buy-sell.component';
4 |
5 | describe('BuySellComponent', () => {
6 | let component: BuySellComponent;
7 | let fixture: ComponentFixture;
8 |
9 | beforeEach(async(() => {
10 | TestBed.configureTestingModule({
11 | declarations: [ BuySellComponent ]
12 | })
13 | .compileComponents();
14 | }));
15 |
16 | beforeEach(() => {
17 | fixture = TestBed.createComponent(BuySellComponent);
18 | component = fixture.componentInstance;
19 | fixture.detectChanges();
20 | });
21 |
22 | it('should create', () => {
23 | expect(component).toBeTruthy();
24 | });
25 | });
26 |
--------------------------------------------------------------------------------
/web/src/app/pages/settings/settings.component.spec.ts:
--------------------------------------------------------------------------------
1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing';
2 |
3 | import { SettingsComponent } from './settings.component';
4 |
5 | describe('SettingsComponent', () => {
6 | let component: SettingsComponent;
7 | let fixture: ComponentFixture;
8 |
9 | beforeEach(async(() => {
10 | TestBed.configureTestingModule({
11 | declarations: [ SettingsComponent ]
12 | })
13 | .compileComponents();
14 | }));
15 |
16 | beforeEach(() => {
17 | fixture = TestBed.createComponent(SettingsComponent);
18 | component = fixture.componentInstance;
19 | fixture.detectChanges();
20 | });
21 |
22 | it('should be created', () => {
23 | expect(component).toBeTruthy();
24 | });
25 | });
26 |
--------------------------------------------------------------------------------
/web/src/app/shared/my-orders/my-orders.component.spec.ts:
--------------------------------------------------------------------------------
1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing';
2 |
3 | import { MyOrdersComponent } from './my-orders.component';
4 |
5 | describe('MyOrdersComponent', () => {
6 | let component: MyOrdersComponent;
7 | let fixture: ComponentFixture;
8 |
9 | beforeEach(async(() => {
10 | TestBed.configureTestingModule({
11 | declarations: [ MyOrdersComponent ]
12 | })
13 | .compileComponents();
14 | }));
15 |
16 | beforeEach(() => {
17 | fixture = TestBed.createComponent(MyOrdersComponent);
18 | component = fixture.componentInstance;
19 | fixture.detectChanges();
20 | });
21 |
22 | it('should create', () => {
23 | expect(component).toBeTruthy();
24 | });
25 | });
26 |
--------------------------------------------------------------------------------
/web/src/app/pages/dashboard/dashboard.component.spec.ts:
--------------------------------------------------------------------------------
1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing';
2 |
3 | import { DashboardComponent } from './dashboard.component';
4 |
5 | describe('DashboardComponent', () => {
6 | let component: DashboardComponent;
7 | let fixture: ComponentFixture;
8 |
9 | beforeEach(async(() => {
10 | TestBed.configureTestingModule({
11 | declarations: [ DashboardComponent ]
12 | })
13 | .compileComponents();
14 | }));
15 |
16 | beforeEach(() => {
17 | fixture = TestBed.createComponent(DashboardComponent);
18 | component = fixture.componentInstance;
19 | fixture.detectChanges();
20 | });
21 |
22 | it('should be created', () => {
23 | expect(component).toBeTruthy();
24 | });
25 | });
26 |
--------------------------------------------------------------------------------
/web/src/app/shared/theme-picker/theme-picker.html:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/web/src/app/shared/theme-picker/theme-picker.spec.ts:
--------------------------------------------------------------------------------
1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing';
2 |
3 | import { ThemePickerComponent } from './theme-picker.component';
4 |
5 | describe('ThemePickerComponent', () => {
6 | let component: ThemePickerComponent;
7 | let fixture: ComponentFixture;
8 |
9 | beforeEach(async(() => {
10 | TestBed.configureTestingModule({
11 | declarations: [ ThemePickerComponent ]
12 | })
13 | .compileComponents();
14 | }));
15 |
16 | beforeEach(() => {
17 | fixture = TestBed.createComponent(ThemePickerComponent);
18 | component = fixture.componentInstance;
19 | fixture.detectChanges();
20 | });
21 |
22 | it('should create', () => {
23 | expect(component).toBeTruthy();
24 | });
25 | });
26 |
--------------------------------------------------------------------------------
/web/src/app/shared/buy-sell-form/buy-sell-form.component.spec.ts:
--------------------------------------------------------------------------------
1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing';
2 |
3 | import { BuySellFormComponent } from './buy-sell-form.component';
4 |
5 | describe('BuySellFormComponent', () => {
6 | let component: BuySellFormComponent;
7 | let fixture: ComponentFixture;
8 |
9 | beforeEach(async(() => {
10 | TestBed.configureTestingModule({
11 | declarations: [ BuySellFormComponent ]
12 | })
13 | .compileComponents();
14 | }));
15 |
16 | beforeEach(() => {
17 | fixture = TestBed.createComponent(BuySellFormComponent);
18 | component = fixture.componentInstance;
19 | fixture.detectChanges();
20 | });
21 |
22 | it('should create', () => {
23 | expect(component).toBeTruthy();
24 | });
25 | });
26 |
--------------------------------------------------------------------------------
/exchanges/okcoin/okcoin_test.go:
--------------------------------------------------------------------------------
1 | package okcoin
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/thrasher-/gocryptotrader/config"
7 | )
8 |
9 | var o OKCoin
10 |
11 | // Please supply your own APIKEYS here for due diligence testing
12 |
13 | const (
14 | apiKey = ""
15 | apiSecret = ""
16 | )
17 |
18 | func TestSetDefaults(t *testing.T) {
19 | o.SetDefaults()
20 | }
21 |
22 | func TestSetup(t *testing.T) {
23 | cfg := config.GetConfig()
24 | cfg.LoadConfig("../../testdata/configtest.json")
25 | okcoinConfig, err := cfg.GetExchangeConfig("OKCOIN International")
26 | if err != nil {
27 | t.Error("Test Failed - OKCoin Setup() init error")
28 | }
29 |
30 | okcoinConfig.AuthenticatedAPISupport = true
31 | okcoinConfig.APIKey = apiKey
32 | okcoinConfig.APISecret = apiSecret
33 |
34 | o.Setup(okcoinConfig)
35 | }
36 |
--------------------------------------------------------------------------------
/web/src/app/app.component.spec.ts:
--------------------------------------------------------------------------------
1 | import { TestBed, async } from '@angular/core/testing';
2 | import { RouterTestingModule } from '@angular/router/testing';
3 | import { AppComponent } from './app.component';
4 | import { ElectronService } from 'app/providers/electron.service';
5 |
6 | describe('AppComponent', () => {
7 | beforeEach(async(() => {
8 | TestBed.configureTestingModule({
9 | declarations: [
10 | AppComponent
11 | ],
12 | providers : [
13 | ElectronService
14 | ],
15 | imports: [RouterTestingModule]
16 | }).compileComponents();
17 | }));
18 |
19 | it('should create the app', async(() => {
20 | const fixture = TestBed.createComponent(AppComponent);
21 | const app = fixture.debugElement.componentInstance;
22 | expect(app).toBeTruthy();
23 | }));
24 | });
25 |
--------------------------------------------------------------------------------
/web/src/app/pages/currency-list/currency-list.component.spec.ts:
--------------------------------------------------------------------------------
1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing';
2 |
3 | import { CurrencyListComponent } from './currency-list.component';
4 |
5 | describe('CurrencyListComponent', () => {
6 | let component: CurrencyListComponent;
7 | let fixture: ComponentFixture;
8 |
9 | beforeEach(async(() => {
10 | TestBed.configureTestingModule({
11 | declarations: [ CurrencyListComponent ]
12 | })
13 | .compileComponents();
14 | }));
15 |
16 | beforeEach(() => {
17 | fixture = TestBed.createComponent(CurrencyListComponent);
18 | component = fixture.componentInstance;
19 | fixture.detectChanges();
20 | });
21 |
22 | it('should create', () => {
23 | expect(component).toBeTruthy();
24 | });
25 | });
26 |
--------------------------------------------------------------------------------
/web/src/app/pages/exchange-grid/exchange-grid.component.spec.ts:
--------------------------------------------------------------------------------
1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing';
2 |
3 | import { ExchangeGridComponent } from './exchange-grid.component';
4 |
5 | describe('ExchangeGridComponent', () => {
6 | let component: ExchangeGridComponent;
7 | let fixture: ComponentFixture;
8 |
9 | beforeEach(async(() => {
10 | TestBed.configureTestingModule({
11 | declarations: [ ExchangeGridComponent ]
12 | })
13 | .compileComponents();
14 | }));
15 |
16 | beforeEach(() => {
17 | fixture = TestBed.createComponent(ExchangeGridComponent);
18 | component = fixture.componentInstance;
19 | fixture.detectChanges();
20 | });
21 |
22 | it('should create', () => {
23 | expect(component).toBeTruthy();
24 | });
25 | });
26 |
--------------------------------------------------------------------------------
/web/src/app/shared/price-history/price-history.component.spec.ts:
--------------------------------------------------------------------------------
1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing';
2 |
3 | import { PriceHistoryComponent } from './price-history.component';
4 |
5 | describe('PriceHistoryComponent', () => {
6 | let component: PriceHistoryComponent;
7 | let fixture: ComponentFixture;
8 |
9 | beforeEach(async(() => {
10 | TestBed.configureTestingModule({
11 | declarations: [ PriceHistoryComponent ]
12 | })
13 | .compileComponents();
14 | }));
15 |
16 | beforeEach(() => {
17 | fixture = TestBed.createComponent(PriceHistoryComponent);
18 | component = fixture.componentInstance;
19 | fixture.detectChanges();
20 | });
21 |
22 | it('should create', () => {
23 | expect(component).toBeTruthy();
24 | });
25 | });
26 |
--------------------------------------------------------------------------------
/web/src/app/shared/trade-history/trade-history.component.spec.ts:
--------------------------------------------------------------------------------
1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing';
2 |
3 | import { TradeHistoryComponent } from './trade-history.component';
4 |
5 | describe('TradeHistoryComponent', () => {
6 | let component: TradeHistoryComponent;
7 | let fixture: ComponentFixture;
8 |
9 | beforeEach(async(() => {
10 | TestBed.configureTestingModule({
11 | declarations: [ TradeHistoryComponent ]
12 | })
13 | .compileComponents();
14 | }));
15 |
16 | beforeEach(() => {
17 | fixture = TestBed.createComponent(TradeHistoryComponent);
18 | component = fixture.componentInstance;
19 | fixture.detectChanges();
20 | });
21 |
22 | it('should create', () => {
23 | expect(component).toBeTruthy();
24 | });
25 | });
26 |
--------------------------------------------------------------------------------
/web/src/app/shared/selected-currency/selected-currency.component.spec.ts:
--------------------------------------------------------------------------------
1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing';
2 |
3 | import { SelectedCurrencyComponent } from './selected-currency.component';
4 |
5 | describe('SelectedCurrencyComponent', () => {
6 | let component: SelectedCurrencyComponent;
7 | let fixture: ComponentFixture;
8 |
9 | beforeEach(async(() => {
10 | TestBed.configureTestingModule({
11 | declarations: [ SelectedCurrencyComponent ]
12 | })
13 | .compileComponents();
14 | }));
15 |
16 | beforeEach(() => {
17 | fixture = TestBed.createComponent(SelectedCurrencyComponent);
18 | component = fixture.componentInstance;
19 | fixture.detectChanges();
20 | });
21 |
22 | it('should create', () => {
23 | expect(component).toBeTruthy();
24 | });
25 | });
26 |
--------------------------------------------------------------------------------
/currency/translation/translation.go:
--------------------------------------------------------------------------------
1 | package translation
2 |
3 | import (
4 | "errors"
5 |
6 | "github.com/thrasher-/gocryptotrader/currency/pair"
7 | )
8 |
9 | var translations = map[pair.CurrencyItem]pair.CurrencyItem{
10 | "BTC": "XBT",
11 | "DOGE": "XDG",
12 | "USD": "USDT",
13 | }
14 |
15 | // GetTranslation returns similar strings for a particular currency
16 | func GetTranslation(currency pair.CurrencyItem) (pair.CurrencyItem, error) {
17 | result, ok := translations[currency]
18 | if !ok {
19 | return "", errors.New("no translation found for specified currency")
20 | }
21 |
22 | return result, nil
23 | }
24 |
25 | // HasTranslation returns whether or not a particular currency has a translation
26 | func HasTranslation(currency pair.CurrencyItem) bool {
27 | _, ok := translations[currency]
28 | if !ok {
29 | return false
30 | }
31 | return true
32 | }
33 |
--------------------------------------------------------------------------------
/web/src/app/providers/electron.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@angular/core';
2 |
3 | // If you import a module but never use any of the imported values other than as TypeScript types,
4 | // the resulting javascript file will look as if you never imported the module at all.
5 | import { ipcRenderer } from 'electron';
6 | import * as childProcess from 'child_process';
7 |
8 | @Injectable()
9 | export class ElectronService {
10 |
11 | ipcRenderer: typeof ipcRenderer;
12 | childProcess: typeof childProcess;
13 |
14 | constructor() {
15 | // Conditional imports
16 | if (this.isElectron()) {
17 | this.ipcRenderer = window.require('electron').ipcRenderer;
18 | this.childProcess = window.require('child_process');
19 | }
20 | }
21 |
22 | isElectron = () => {
23 | return window && window.process && window.process.type;
24 | }
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/web/src/app/shared/exchange-currency-ticker/exchange-currency-ticker.component.spec.ts:
--------------------------------------------------------------------------------
1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing';
2 |
3 | import { ExchangeCurrencyTickerComponent } from './exchange-currency-ticker.component';
4 |
5 | describe('ExchangeCurrencyTickerComponent', () => {
6 | let component: ExchangeCurrencyTickerComponent;
7 | let fixture: ComponentFixture;
8 |
9 | beforeEach(async(() => {
10 | TestBed.configureTestingModule({
11 | declarations: [ ExchangeCurrencyTickerComponent ]
12 | })
13 | .compileComponents();
14 | }));
15 |
16 | beforeEach(() => {
17 | fixture = TestBed.createComponent(ExchangeCurrencyTickerComponent);
18 | component = fixture.componentInstance;
19 | fixture.detectChanges();
20 | });
21 |
22 | it('should be created', () => {
23 | expect(component).toBeTruthy();
24 | });
25 | });
26 |
--------------------------------------------------------------------------------
/web/src/app/shared/exchange-currency-ticker/exchange-currency-ticker.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit, Input } from '@angular/core';
2 | @Component({
3 | selector: 'app-exchange-currency-ticker',
4 | templateUrl: './exchange-currency-ticker.component.html',
5 | styleUrls: ['./exchange-currency-ticker.component.scss'],
6 | })
7 | export class ExchangeCurrencyTickerComponent implements OnInit {
8 | @Input('ticker') ticker: TickerUpdate;
9 |
10 | constructor() {}
11 | ngOnInit() { }
12 |
13 | }
14 |
15 |
16 | export interface CurrencyPair {
17 | delimiter: string;
18 | first_currency: string;
19 | second_currency: string;
20 | }
21 |
22 | export interface TickerUpdate {
23 | Pair: CurrencyPair;
24 | CurrencyPair: string;
25 | Last: number;
26 | High: number;
27 | Low: number;
28 | Bid: number;
29 | Ask: number;
30 | Volume: number;
31 | PriceATH: number;
32 | Exchange:string;
33 | }
34 |
35 |
--------------------------------------------------------------------------------
/web/src/app/shared/all-enabled-currency-tickers/all-enabled-currency-tickers.component.spec.ts:
--------------------------------------------------------------------------------
1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing';
2 |
3 | import { AllEnabledCurrencyTickersComponent } from './all-enabled-currency-tickers.component';
4 |
5 | describe('AllEnabledCurrencyTickersComponent', () => {
6 | let component: AllEnabledCurrencyTickersComponent;
7 | let fixture: ComponentFixture;
8 |
9 | beforeEach(async(() => {
10 | TestBed.configureTestingModule({
11 | declarations: [ AllEnabledCurrencyTickersComponent ]
12 | })
13 | .compileComponents();
14 | }));
15 |
16 | beforeEach(() => {
17 | fixture = TestBed.createComponent(AllEnabledCurrencyTickersComponent);
18 | component = fixture.componentInstance;
19 | fixture.detectChanges();
20 | });
21 |
22 | it('should be created', () => {
23 | expect(component).toBeTruthy();
24 | });
25 | });
26 |
--------------------------------------------------------------------------------
/exchanges/bitfinex/bitfinex_wrapper_test.go:
--------------------------------------------------------------------------------
1 | package bitfinex
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/thrasher-/gocryptotrader/currency/pair"
7 | "github.com/thrasher-/gocryptotrader/exchanges/ticker"
8 | )
9 |
10 | func TestStart(t *testing.T) {
11 | start := Bitfinex{}
12 | start.Start()
13 | }
14 |
15 | func TestRun(t *testing.T) {
16 | run := Bitfinex{}
17 | run.Run()
18 | }
19 |
20 | func TestGetTickerPrice(t *testing.T) {
21 | getTickerPrice := Bitfinex{}
22 | _, err := getTickerPrice.GetTickerPrice(pair.NewCurrencyPair("BTC", "USD"),
23 | ticker.Spot)
24 | if err != nil {
25 | t.Errorf("Test Failed - Bitfinex GetTickerPrice() error: %s", err)
26 | }
27 | }
28 |
29 | func TestGetOrderbookEx(t *testing.T) {
30 | getOrderBookEx := Bitfinex{}
31 | _, err := getOrderBookEx.GetOrderbookEx(pair.NewCurrencyPair("BTC", "USD"),
32 | ticker.Spot)
33 | if err != nil {
34 | t.Errorf("Test Failed - Bitfinex GetOrderbookEx() error: %s", err)
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/web/src/app/app.component.scss:
--------------------------------------------------------------------------------
1 | .container {
2 | height: 100vh;
3 | min-height:100%;
4 | }
5 |
6 | .main {
7 | display: flex;
8 | align-items: center;
9 | justify-content: center;
10 | padding: 20px 70px 0;
11 | min-width: 86%;
12 | margin: 10px auto;
13 | overflow-x: hidden;
14 | margin-top:4rem;
15 | }
16 |
17 | .sidebar {
18 | width: 14%;
19 | position: fixed;
20 | margin-top: 4rem;
21 | }
22 |
23 | .navbar {
24 | position: fixed;
25 | width: 100%;
26 | z-index: 2;
27 | }
28 |
29 | .dashboard-highlight {
30 | color: green !important;
31 | }
32 |
33 | .trading-highlight {
34 | color: orangered !important;
35 | }
36 |
37 | .history-highlight {
38 | color: cornflowerblue !important;
39 | }
40 |
41 | .wallet-highlight {
42 | color: blueviolet !important;
43 | }
44 |
45 | .settings-highlight {
46 | color: magenta !important;
47 | }
48 |
49 | .donate-highlight {
50 | color: goldenrod!important;
51 | }
--------------------------------------------------------------------------------
/doc/coding_style.md:
--------------------------------------------------------------------------------
1 | Coding Style
2 | ===============
3 |
4 | In order to maintain a consistent style across the codebase, the following coding style has been adopted:
5 |
6 | - Function names use PascalCase (func SomeFunc()).
7 | - Function names using acronyms are capitilised (func SendHTTPRequest()).
8 | - Variable names use CamelCase (var someVar()).
9 | - Coding style uses gofmt.
10 | - Const variables are CamelCase depending on exported items.
11 | - In line with gofmt, for loops and if statements don't require paranthesis.
12 |
13 | Block style example:
14 | ```go
15 | func SendHTTPRequest(method, path string, headers map[string]string, body io.Reader) (string, error) {
16 | result := strings.ToUpper(method)
17 |
18 | if result != "POST" && result != "GET" && result != "DELETE" {
19 | return "", errors.New("Invalid HTTP method specified.")
20 | }
21 |
22 | req, err := http.NewRequest(method, path, body)
23 |
24 | if err != nil {
25 | return "", err
26 | }
27 |
28 | for k, v := range headers {
29 | req.Header.Add(k, v)
30 | }
31 | ...
32 | }
33 | ```
34 |
--------------------------------------------------------------------------------
/orders_test.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 | func TestNewOrder(t *testing.T) {
8 | ID := NewOrder("ANX", 2000, 20.00)
9 | if ID != 0 {
10 | t.Error("Test Failed - Orders_test.go NewOrder() - Error")
11 | }
12 | ID = NewOrder("BATMAN", 400, 25.00)
13 | if ID != 1 {
14 | t.Error("Test Failed - Orders_test.go NewOrder() - Error")
15 | }
16 | }
17 |
18 | func TestDeleteOrder(t *testing.T) {
19 | if value := DeleteOrder(0); !value {
20 | t.Error("Test Failed - Orders_test.go DeleteOrder() - Error")
21 | }
22 | if value := DeleteOrder(100); value {
23 | t.Error("Test Failed - Orders_test.go DeleteOrder() - Error")
24 | }
25 | }
26 |
27 | func TestGetOrdersByExchange(t *testing.T) {
28 | if value := GetOrdersByExchange("ANX"); len(value) != 0 {
29 | t.Error("Test Failed - Orders_test.go GetOrdersByExchange() - Error")
30 | }
31 | }
32 |
33 | func TestGetOrderByOrderID(t *testing.T) {
34 | if value := GetOrderByOrderID(69); value != nil {
35 | t.Error("Test Failed - Orders_test.go GetOrdersByExchange() - Error")
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/web/src/app/pages/dashboard/dashboard.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | {{tile.title}}
10 | {{tile.subTitle}}
11 |
12 |
13 | {{tile.content}}
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/web/src/app/services/theme-storage/theme-storage.service.ts:
--------------------------------------------------------------------------------
1 | import {Injectable, EventEmitter} from '@angular/core';
2 |
3 | export interface DocsSiteTheme {
4 | href: string;
5 | accent: string;
6 | primary: string;
7 | isDark?: boolean;
8 | isDefault?: boolean;
9 | }
10 |
11 |
12 | @Injectable()
13 | export class ThemeStorageService {
14 | static storageKey = 'docs-theme-storage-current';
15 |
16 | public onThemeUpdate: EventEmitter = new EventEmitter();
17 |
18 | public storeTheme(theme: DocsSiteTheme) {
19 | try {
20 | window.localStorage[ThemeStorageService.storageKey] = JSON.stringify(theme);
21 | } catch (e) { }
22 |
23 | this.onThemeUpdate.emit(theme);
24 | }
25 |
26 | public getStoredTheme(): DocsSiteTheme {
27 | try {
28 | return JSON.parse(window.localStorage[ThemeStorageService.storageKey] || null);
29 | } catch (e) {
30 | return null;
31 | }
32 | }
33 |
34 | public clearStorage() {
35 | try {
36 | window.localStorage.removeItem(ThemeStorageService.storageKey);
37 | } catch (e) { }
38 | }
39 | }
--------------------------------------------------------------------------------
/web/protractor.conf.js:
--------------------------------------------------------------------------------
1 | // Protractor configuration file, see link for more information
2 | // https://github.com/angular/protractor/blob/master/lib/config.ts
3 |
4 | const { SpecReporter } = require('jasmine-spec-reporter');
5 |
6 | exports.config = {
7 | allScriptsTimeout: 25000,
8 | getPageTimeout: 15000,
9 | delayBrowserTimeInSeconds: 0,
10 | specs: [
11 | './e2e/**/*.e2e-spec.ts'
12 | ],
13 | capabilities: {
14 | 'browserName': 'chrome',
15 | chromeOptions: {
16 | binary: './node_modules/electron/dist/electron.exe',
17 | args: ['--test-type=webdriver', 'app=dist/main.js']
18 | }
19 | },
20 | directConnect: true,
21 | baseUrl: 'http://localhost:4200/',
22 | framework: 'jasmine2',
23 | jasmineNodeOpts: {
24 | showColors: true,
25 | defaultTimeoutInterval: 30000,
26 | print: function () { }
27 | },
28 | beforeLaunch: function () {
29 | require('ts-node').register({
30 | project: 'e2e/tsconfig.e2e.json'
31 | });
32 | },
33 | onPrepare() {
34 | jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } }));
35 | }
36 | };
37 |
--------------------------------------------------------------------------------
/exchanges/huobi/huobi_test.go:
--------------------------------------------------------------------------------
1 | package huobi
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/thrasher-/gocryptotrader/config"
7 | )
8 |
9 | var h HUOBI
10 |
11 | // Please supply your own APIKEYS here for due diligence testing
12 |
13 | const (
14 | apiKey = ""
15 | apiSecret = ""
16 | )
17 |
18 | func TestSetDefaults(t *testing.T) {
19 | h.SetDefaults()
20 | }
21 |
22 | func TestSetup(t *testing.T) {
23 | cfg := config.GetConfig()
24 | cfg.LoadConfig("../../testdata/configtest.json")
25 | huobiConfig, err := cfg.GetExchangeConfig("Huobi")
26 | if err != nil {
27 | t.Error("Test Failed - Huobi Setup() init error")
28 | }
29 |
30 | huobiConfig.AuthenticatedAPISupport = true
31 | huobiConfig.APIKey = apiKey
32 | huobiConfig.APISecret = apiSecret
33 |
34 | h.Setup(huobiConfig)
35 | }
36 |
37 | func TestGetFee(t *testing.T) {
38 | t.Parallel()
39 | if h.GetFee() != 0 {
40 | t.Error("test failed - Huobi GetFee() error")
41 | }
42 | }
43 |
44 | func TestGetTicker(t *testing.T) {
45 | t.Parallel()
46 | _, err := h.GetTicker("btcusd")
47 | if err == nil {
48 | t.Error("test failed - Huobi GetTicker() error", err)
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2014-2017 The GoCryptoTrader Developers
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/web/src/app/shared/exchange-currency-ticker/exchange-currency-ticker.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | {{ticker?.Exchange}} {{ticker?.CurrencyPair}} Ticker update
4 |
5 |
6 |
7 |
8 | Last: {{ticker?.Last | number:'1.0-1'}}
9 |
10 |
11 | Low: {{ticker?.Low | number:'1.0-1'}}
12 |
13 |
14 | High: {{ticker?.High | number:'1.0-1'}}
15 |
16 |
17 |
18 | Bid: {{ticker?.Bid | number:'1.0-1'}}
19 |
20 |
21 | Ask: {{ticker?.Ask | number:'1.0-1'}}
22 |
23 |
24 | Volume: {{ticker?.Volume | number:'1.0-1'}}
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/web/src/test.ts:
--------------------------------------------------------------------------------
1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files
2 |
3 | import 'zone.js/dist/long-stack-trace-zone';
4 | import 'zone.js/dist/proxy.js';
5 | import 'zone.js/dist/sync-test';
6 | import 'zone.js/dist/jasmine-patch';
7 | import 'zone.js/dist/async-test';
8 | import 'zone.js/dist/fake-async-test';
9 | import { getTestBed } from '@angular/core/testing';
10 | import {
11 | BrowserDynamicTestingModule,
12 | platformBrowserDynamicTesting
13 | } from '@angular/platform-browser-dynamic/testing';
14 |
15 | // Unfortunately there's no typing for the `__karma__` variable. Just declare it as any.
16 | declare const __karma__: any;
17 | declare const require: any;
18 |
19 | // Prevent Karma from running prematurely.
20 | __karma__.loaded = function () {};
21 |
22 | // First, initialize the Angular testing environment.
23 | getTestBed().initTestEnvironment(
24 | BrowserDynamicTestingModule,
25 | platformBrowserDynamicTesting()
26 | );
27 | // Then we find all the tests.
28 | const context = require.context('./', true, /\.spec\.ts$/);
29 | // And load the modules.
30 | context.keys().map(context);
31 | // Finally, start Karma to run the tests.
32 | __karma__.start();
33 |
--------------------------------------------------------------------------------
/web/src/app/pages/home/home.component.spec.ts:
--------------------------------------------------------------------------------
1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing';
2 |
3 | import { HomeComponent } from './home.component';
4 |
5 | describe('HomeComponent', () => {
6 | let component: HomeComponent;
7 | let fixture: ComponentFixture;
8 |
9 | beforeEach(async(() => {
10 | TestBed.configureTestingModule({
11 | declarations: [ HomeComponent ]
12 | })
13 | .compileComponents();
14 | }));
15 |
16 | beforeEach(() => {
17 | fixture = TestBed.createComponent(HomeComponent);
18 | component = fixture.componentInstance;
19 | fixture.detectChanges();
20 | });
21 |
22 | it('should create', () => {
23 | expect(component).toBeTruthy();
24 | });
25 |
26 | it(`should have as title 'App works !'`, async(() => {
27 | fixture = TestBed.createComponent(HomeComponent);
28 | const app = fixture.debugElement.componentInstance;
29 | expect(app.title).toEqual('App works !');
30 | }));
31 |
32 | it('should render title in a h1 tag', async(() => {
33 | fixture = TestBed.createComponent(HomeComponent);
34 | fixture.detectChanges();
35 | const compiled = fixture.debugElement.nativeElement;
36 | expect(compiled.querySelector('h1').textContent).toContain('App works !');
37 | }));
38 | });
39 |
--------------------------------------------------------------------------------
/web/src/app/services/websocket/websocket.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@angular/core';
2 | import {Subject, Observable, Observer } from 'rxjs/Rx';
3 |
4 | @Injectable()
5 | export class WebsocketService {
6 | constructor() { }
7 |
8 | private subject: Subject;
9 |
10 | public connect(url): Subject {
11 | if (!this.subject) {
12 | this.subject = this.create(url);
13 | }
14 | return this.subject;
15 | }
16 |
17 | private authenticateMessage = {
18 | Event:'auth',
19 | data:{"username":"admin","password":"e7cf3ef4f17c3999a94f2c6f612e8a888e5b1026878e4e19398b23bd38ec221a"},
20 | }
21 |
22 | private isAuth = false;
23 |
24 | private create(url): Subject {
25 | let ws = new WebSocket(url);
26 |
27 | let observable = Observable.create(
28 | (obs: Observer) => {
29 | ws.onmessage = obs.next.bind(obs);
30 | ws.onerror = obs.error.bind(obs);
31 | ws.onclose = obs.complete.bind(obs);
32 | return ws.close.bind(ws);
33 | })
34 | let observer = {
35 | next: (data: any) => {
36 | if (ws.readyState === WebSocket.OPEN) {
37 | ws.send(JSON.stringify(this.authenticateMessage));
38 |
39 | ws.send(JSON.stringify(data));
40 | }
41 | }
42 | }
43 | return Subject.create(observer, observable);
44 | }
45 | }
--------------------------------------------------------------------------------
/web/src/app/pages/currency-list/currency-list.component.html:
--------------------------------------------------------------------------------
1 |
2 | Poloniex
3 |
4 | attach_money
5 | BTC_USD
6 |
7 |
8 |
9 | attach_money
10 | LTC_USD
11 |
12 |
13 |
14 | attach_money
15 | ETH_USD
16 |
17 |
18 |
19 | Kraken
20 |
21 | attach_money
22 | BTC_USD
23 |
24 |
25 |
26 | attach_money
27 | LTC_USD
28 |
29 |
30 |
31 | attach_money
32 | ETH_USD
33 |
34 |
35 |
--------------------------------------------------------------------------------
/currency/translation/translation_test.go:
--------------------------------------------------------------------------------
1 | package translation
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/thrasher-/gocryptotrader/currency/pair"
7 | )
8 |
9 | func TestGetTranslation(t *testing.T) {
10 | currencyPair := pair.NewCurrencyPair("BTC", "USD")
11 | expected := pair.CurrencyItem("XBT")
12 | actual, err := GetTranslation(currencyPair.FirstCurrency)
13 | if err != nil {
14 | t.Error("GetTranslation: failed to retrieve translation for BTC")
15 | }
16 |
17 | if expected != actual {
18 | t.Error("GetTranslation: translation result was different to expected result")
19 | }
20 |
21 | currencyPair.FirstCurrency = "ETH"
22 | _, err = GetTranslation(currencyPair.FirstCurrency)
23 | if err == nil {
24 | t.Error("GetTranslation: no error on non translatable currency")
25 | }
26 | }
27 |
28 | func TestHasTranslation(t *testing.T) {
29 | currencyPair := pair.NewCurrencyPair("BTC", "USD")
30 | expected := true
31 | actual := HasTranslation(currencyPair.FirstCurrency)
32 | if expected != actual {
33 | t.Error("HasTranslation: translation result was different to expected result")
34 | }
35 |
36 | currencyPair.FirstCurrency = "ETH"
37 | expected = false
38 | actual = HasTranslation(currencyPair.FirstCurrency)
39 | if expected != actual {
40 | t.Error("HasTranslation: translation result was different to expected result")
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/web/.angular-cli.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
3 | "project": {
4 | "name": "angular-electron"
5 | },
6 | "apps": [
7 | {
8 | "root": "src",
9 | "outDir": "dist",
10 | "assets": [
11 | "assets",
12 | "favicon.ico"
13 | ],
14 | "index": "index.html",
15 | "main": "main.ts",
16 | "polyfills": "polyfills.ts",
17 | "test": "test.ts",
18 | "tsconfig": "tsconfig.app.json",
19 | "testTsconfig": "tsconfig.spec.json",
20 | "prefix": "app",
21 | "styles": [
22 | "styles.scss"
23 | ],
24 | "scripts": [
25 | ],
26 | "environmentSource": "environments/environment.ts",
27 | "environments": {
28 | "dev": "environments/environment.ts",
29 | "prod": "environments/environment.prod.ts"
30 | }
31 | }
32 | ],
33 | "e2e": {
34 | "protractor": {
35 | "config": "./protractor.conf.js"
36 | }
37 | },
38 | "lint": [
39 | {
40 | "project": "src/tsconfig.app.json"
41 | },
42 | {
43 | "project": "src/tsconfig.spec.json"
44 | },
45 | {
46 | "project": "e2e/tsconfig.e2e.json"
47 | }
48 | ],
49 | "test": {
50 | "karma": {
51 | "config": "./karma.conf.js"
52 | }
53 | },
54 | "defaults": {
55 | "styleExt": "scss",
56 | "component": {
57 | }
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/web/src/app/services/websocket-handler/websocket-handler.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@angular/core';
2 | import { Observable, Subject } from 'rxjs/Rx';
3 | import { WebsocketService } from './../../services/websocket/websocket.service';
4 |
5 | const WEBSOCKET_URL = 'ws://localhost:9050/ws';
6 |
7 | export interface Message {
8 | Event: string,
9 | data:any,
10 | Exchange:string,
11 | AssetType:string
12 | }
13 |
14 | @Injectable()
15 | export class WebsocketHandlerService {
16 | public messages: Subject;
17 |
18 | private authenticateMessage = {
19 | Event:'auth',
20 | data:{"username":"admin","password":"e7cf3ef4f17c3999a94f2c6f612e8a888e5b1026878e4e19398b23bd38ec221a"},
21 | }
22 |
23 | public authenticate() {
24 | this.messages.next(this.authenticateMessage);
25 | }
26 |
27 | constructor(wsService: WebsocketService) {
28 | this.messages = >wsService
29 | .connect(WEBSOCKET_URL)
30 | .map((response: MessageEvent): Message => {
31 |
32 | let data = JSON.parse(response.data);
33 | // variables aren't consistent yet. Here's a hack!
34 | var dataData = data.Data === undefined ? data.data : data.Data;
35 | var eventEvent = data.Event === undefined ? data.event : data.Event;
36 | return {
37 | Event: eventEvent,
38 | data: dataData,
39 | Exchange: data.exchange,
40 | AssetType: data.assetType
41 | }
42 | });
43 | }
44 | }
--------------------------------------------------------------------------------
/web/karma.conf.js:
--------------------------------------------------------------------------------
1 | // Karma configuration file, see link for more information
2 | // https://karma-runner.github.io/0.13/config/configuration-file.html
3 |
4 | module.exports = function (config) {
5 | config.set({
6 | basePath: '',
7 | frameworks: ['jasmine', '@angular/cli'],
8 | plugins: [
9 | require('karma-jasmine'),
10 | require('karma-chrome-launcher'),
11 | require('karma-jasmine-html-reporter'),
12 | require('karma-coverage-istanbul-reporter'),
13 | require('@angular/cli/plugins/karma')
14 | ],
15 | client:{
16 | clearContext: false // leave Jasmine Spec Runner output visible in browser
17 | },
18 | files: [
19 | { pattern: './src/test.ts', watched: false }
20 | ],
21 | preprocessors: {
22 | './src/test.ts': ['@angular/cli']
23 | },
24 | mime: {
25 | 'text/x-typescript': ['ts','tsx']
26 | },
27 | coverageIstanbulReporter: {
28 | reports: [ 'html', 'lcovonly' ],
29 | fixWebpackSourcePaths: true
30 | },
31 | angularCli: {
32 | environment: 'dev'
33 | },
34 | reporters: config.angularCli && config.angularCli.codeCoverage
35 | ? ['progress', 'coverage-istanbul']
36 | : ['progress', 'kjhtml'],
37 | port: 9876,
38 | colors: true,
39 | logLevel: config.LOG_INFO,
40 | autoWatch: true,
41 | browsers: ['Chrome'],
42 | singleRun: false
43 | });
44 | };
45 |
--------------------------------------------------------------------------------
/web/src/app/services/style-manager/style-manager.service.ts:
--------------------------------------------------------------------------------
1 | import {Injectable} from '@angular/core';
2 | /**
3 | * Class for managing stylesheets. Stylesheets are loaded into named slots so that they can be
4 | * removed or changed later.
5 | */
6 | @Injectable()
7 | export class StyleManagerService {
8 | /**
9 | * Set the stylesheet with the specified key.
10 | */
11 | setStyle(key: string, href: string) {
12 | getLinkElementForKey(key).setAttribute('href', href);
13 | }
14 |
15 | /**
16 | * Remove the stylesheet with the specified key.
17 | */
18 | removeStyle(key: string) {
19 | const existingLinkElement = getExistingLinkElementByKey(key);
20 | if (existingLinkElement) {
21 | document.head.removeChild(existingLinkElement);
22 | }
23 | }
24 | }
25 |
26 | function getLinkElementForKey(key: string) {
27 | return getExistingLinkElementByKey(key) || createLinkElementWithKey(key);
28 | }
29 |
30 | function getExistingLinkElementByKey(key: string) {
31 | return document.head.querySelector(`link[rel="stylesheet"].${getClassNameForKey(key)}`);
32 | }
33 |
34 | function createLinkElementWithKey(key: string) {
35 | const linkEl = document.createElement('link');
36 | linkEl.setAttribute('rel', 'stylesheet');
37 | linkEl.classList.add(getClassNameForKey(key));
38 | document.head.appendChild(linkEl);
39 | return linkEl;
40 | }
41 |
42 | function getClassNameForKey(key: string) {
43 | return `style-manager-${key}`;
44 | }
--------------------------------------------------------------------------------
/web/src/styles.scss:
--------------------------------------------------------------------------------
1 | /* You can add global styles to this file, and also import other style files */
2 |
3 | html,
4 | body {
5 | margin: 0;
6 | padding: 0;
7 | font-family: Roboto,Helvetica Neue Light,Helvetica Neue,Helvetica,Arial,Lucida Grande,sans-serif;
8 | }
9 |
10 | .loading-spinner {
11 | margin-left: 50%;
12 | margin-right: 50%;
13 | }
14 |
15 | ////////////////////////////////////////////////////////////////
16 | // Default settings for cards
17 | ////////////////////////////////////////////////////////////////
18 | .card {
19 | width: 80%;
20 | margin: 10px auto;
21 | }
22 |
23 | ////////////////////////////////////////////////////////////////
24 | // Default settings for expandable tile menus
25 | ////////////////////////////////////////////////////////////////
26 | .mat-expansion-panel {
27 | width: 80%;
28 | margin: 0px auto !important;
29 | }
30 |
31 | .mat-expansion-panel-header-title,
32 | .mat-expansion-panel-header-description {
33 | flex-basis: 0;
34 | }
35 |
36 | .mat-expansion-panel-header-description {
37 | justify-content: space-between;
38 | align-items: center;
39 | }
40 |
41 | .mat-expansion-panel-spacing {
42 | margin: 16px auto !important;
43 | width: 85%;
44 | }
45 |
46 | .mat-drawer {
47 | background: none !important;
48 | }
49 |
50 | @import '~@angular/material/prebuilt-themes/indigo-pink.css';
51 |
52 | /*
53 | deeppurple-amber.css
54 | indigo-pink.css
55 | pink-bluegrey.css
56 | purple-green.css
57 | */
--------------------------------------------------------------------------------
/web/src/app/services/sidebar/sidebar.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@angular/core';
2 | import { MatSidenav, MatDrawerToggleResult } from '@angular/material';
3 |
4 | @Injectable()
5 | export class SidebarService {
6 | private sidenav: MatSidenav;
7 |
8 | /**
9 | * Setter for sidenav.
10 | *
11 | * @param {MatSidnav} sidenav
12 | */
13 | public setSidenav(sidenav: MatSidenav) {
14 | this.sidenav = sidenav;
15 | }
16 |
17 | /**
18 | * Open this sidenav, and return a Promise that will resolve when it's fully opened (or get rejected if it didn't).
19 | *
20 | * @returns Promise
21 | */
22 | public open(): Promise {
23 | this.sidenav.open();
24 |
25 | return;
26 | }
27 |
28 | /**
29 | * Close this sidenav, and return a Promise that will resolve when it's fully closed (or get rejected if it didn't).
30 | *
31 | * @returns Promise
32 | */
33 | public close(): Promise {
34 | this.sidenav.close();
35 | return;
36 | }
37 |
38 | /**
39 | * Toggle this sidenav. This is equivalent to calling open() when it's already opened, or close() when it's closed.
40 | *
41 | * @param {boolean} isOpen Whether the sidenav should be open.
42 | *
43 | * @returns {Promise}
44 | */
45 | public toggle(isOpen?: boolean): Promise {
46 | this.sidenav.toggle(isOpen);
47 | return;
48 | }
49 | }
--------------------------------------------------------------------------------
/web/src/app/shared/theme-picker/theme-picker.scss:
--------------------------------------------------------------------------------
1 | $theme-picker-menu-padding: 8px;
2 | $theme-picker-grid-cell-size: 48px;
3 | $theme-picker-grid-cells-per-row: 2;
4 | $theme-picker-swatch-size: 36px;
5 | $theme-picker-accent-stripe-size: 6px;
6 |
7 |
8 | .docs-theme-picker-menu {
9 | .mat-menu-content {
10 | padding: $theme-picker-menu-padding;
11 | }
12 |
13 | [mat-menu-item] {
14 | flex: 0 0 auto;
15 | padding: 0;
16 | overflow: hidden;
17 | }
18 |
19 | .docs-theme-picker-swatch {
20 | position: relative;
21 | width: $theme-picker-swatch-size;
22 | height: $theme-picker-swatch-size;
23 | margin: ($theme-picker-grid-cell-size - $theme-picker-swatch-size) / 2;
24 | border-radius: 50%;
25 | overflow: hidden;
26 |
27 | .docs-theme-chosen-icon {
28 | color: white;
29 | position: absolute;
30 | left: 50%; top: 50%;
31 | transform: translate(-50%, -50%);
32 | }
33 |
34 | &::after {
35 | content: '';
36 | position: absolute;
37 | top: 0;
38 | left: 0;
39 | width: 100%;
40 | height: 100%;
41 | box-sizing: border-box;
42 | border: 1px solid rgba(0,0,0,.2);
43 | border-radius: 50%;
44 | }
45 | }
46 |
47 | .docs-theme-picker-primary {
48 | width: 100%;
49 | height: 100%;
50 | }
51 |
52 | .docs-theme-picker-accent {
53 | position: absolute;
54 | bottom: $theme-picker-accent-stripe-size;
55 | width: 100%;
56 | height: $theme-picker-accent-stripe-size;
57 | }
58 | }
--------------------------------------------------------------------------------
/exchanges/coinut/coinut_websocket.go:
--------------------------------------------------------------------------------
1 | package coinut
2 |
3 | import (
4 | "log"
5 | "net/http"
6 |
7 | "github.com/gorilla/websocket"
8 | "github.com/thrasher-/gocryptotrader/common"
9 | )
10 |
11 | const COINUT_WEBSOCKET_URL = "wss://wsapi.coinut.com"
12 |
13 | func (c *COINUT) WebsocketClient() {
14 | for c.Enabled && c.Websocket {
15 | var Dialer websocket.Dialer
16 | var err error
17 | c.WebsocketConn, _, err = Dialer.Dial(c.WebsocketURL, http.Header{})
18 |
19 | if err != nil {
20 | log.Printf("%s Unable to connect to Websocket. Error: %s\n", c.Name, err)
21 | continue
22 | }
23 |
24 | if c.Verbose {
25 | log.Printf("%s Connected to Websocket.\n", c.Name)
26 | }
27 |
28 | err = c.WebsocketConn.WriteMessage(websocket.TextMessage, []byte(`{"messageType": "hello_world"}`))
29 |
30 | if err != nil {
31 | log.Println(err)
32 | return
33 | }
34 |
35 | for c.Enabled && c.Websocket {
36 | msgType, resp, err := c.WebsocketConn.ReadMessage()
37 | if err != nil {
38 | log.Println(err)
39 | break
40 | }
41 |
42 | switch msgType {
43 | case websocket.TextMessage:
44 | type MsgType struct {
45 | MessageType string `json:"messageType"`
46 | }
47 |
48 | msgType := MsgType{}
49 | err := common.JSONDecode(resp, &msgType)
50 | if err != nil {
51 | log.Println(err)
52 | continue
53 | }
54 | log.Println(string(resp))
55 | }
56 | }
57 | c.WebsocketConn.Close()
58 | log.Printf("%s Websocket client disconnected.", c.Name)
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/orders.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | const (
4 | limitOrder = iota
5 | marketOrder
6 | )
7 |
8 | // Orders variable holds an array of pointers to order structs
9 | var Orders []*Order
10 |
11 | // Order struct holds order values
12 | type Order struct {
13 | OrderID int
14 | Exchange string
15 | Type int
16 | Amount float64
17 | Price float64
18 | }
19 |
20 | // NewOrder creates a new order and returns a an orderID
21 | func NewOrder(Exchange string, amount, price float64) int {
22 | order := &Order{}
23 | if len(Orders) == 0 {
24 | order.OrderID = 0
25 | } else {
26 | order.OrderID = len(Orders)
27 | }
28 |
29 | order.Exchange = Exchange
30 | order.Amount = amount
31 | order.Price = price
32 | Orders = append(Orders, order)
33 | return order.OrderID
34 | }
35 |
36 | // DeleteOrder deletes orders by ID and returns state
37 | func DeleteOrder(orderID int) bool {
38 | for i := range Orders {
39 | if Orders[i].OrderID == orderID {
40 | Orders = append(Orders[:i], Orders[i+1:]...)
41 | return true
42 | }
43 | }
44 | return false
45 | }
46 |
47 | // GetOrdersByExchange returns order pointer grouped by exchange
48 | func GetOrdersByExchange(exchange string) []*Order {
49 | orders := []*Order{}
50 | for i := range Orders {
51 | if Orders[i].Exchange == exchange {
52 | orders = append(orders, Orders[i])
53 | }
54 | }
55 | if len(orders) > 0 {
56 | return orders
57 | }
58 | return nil
59 | }
60 |
61 | // GetOrderByOrderID returns order pointer by ID
62 | func GetOrderByOrderID(orderID int) *Order {
63 | for i := range Orders {
64 | if Orders[i].OrderID == orderID {
65 | return Orders[i]
66 | }
67 | }
68 | return nil
69 | }
70 |
--------------------------------------------------------------------------------
/web/src/app/app.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit,ViewChild } from '@angular/core';
2 | import { ElectronService } from './providers/electron.service';
3 | import { MatSidenav } from '@angular/material';
4 | import { SidebarService } from './services/sidebar/sidebar.service';
5 | import { Router, NavigationEnd } from '@angular/router';
6 |
7 | @Component({
8 | selector: 'app-root',
9 | templateUrl: './app.component.html',
10 | styleUrls: ['./app.component.scss'],
11 | })
12 | export class AppComponent {
13 | sidebarService: SidebarService
14 | public currentUrl:string;
15 | @ViewChild('sidenav') public sidenav: MatSidenav;
16 |
17 | constructor(public electronService: ElectronService,something: SidebarService, private router:Router) {
18 |
19 | if (electronService.isElectron()) {
20 | console.log('Mode electron');
21 | // Check if electron is correctly injected (see externals in webpack.config.js)
22 | console.log('c', electronService.ipcRenderer);
23 | // Check if nodeJs childProcess is correctly injected (see externals in webpack.config.js)
24 | console.log('c', electronService.childProcess);
25 | } else {
26 | console.log('Mode web');
27 | }
28 |
29 | this.sidebarService = something;
30 |
31 | router.events.subscribe(event => {
32 |
33 | if (event instanceof NavigationEnd ) {
34 | console.log("current url",event.url); // event.url has current url
35 | this.currentUrl = event.url;
36 | }
37 | });
38 | }
39 |
40 | ngOnInit() {
41 | this.sidebarService.setSidenav(this.sidenav);
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/web/package.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | var packager = require('electron-packager');
4 | const pkg = require('./package.json');
5 | const argv = require('minimist')(process.argv.slice(1));
6 |
7 | const appName = argv.name || pkg.name;
8 | const buildVersion = pkg.version || '1.0';
9 | const shouldUseAsar = argv.asar || false;
10 | const shouldBuildAll = argv.all || false;
11 | const arch = argv.arch || 'all';
12 | const platform = argv.platform || 'darwin';
13 |
14 | const DEFAULT_OPTS = {
15 | dir: './dist',
16 | name: appName,
17 | asar: shouldUseAsar,
18 | buildVersion: buildVersion
19 | };
20 |
21 |
22 | pack(platform, arch, function done(err, appPath) {
23 | if (err) {
24 | console.log(err);
25 | } else {
26 | console.log('Application packaged successfuly!', appPath);
27 | }
28 |
29 | });
30 |
31 | function pack(plat, arch, cb) {
32 | // there is no darwin ia32 electron
33 | if (plat === 'darwin' && arch === 'ia32') return;
34 |
35 | let icon = 'src/favicon';
36 |
37 | if (icon) {
38 | DEFAULT_OPTS.icon = icon + (() => {
39 | let extension = '.png';
40 | if (plat === 'darwin') {
41 | extension = '.icns';
42 | } else if (plat === 'win32') {
43 | extension = '.ico';
44 | }
45 | return extension;
46 | })();
47 | }
48 |
49 | const opts = Object.assign({}, DEFAULT_OPTS, {
50 | platform: plat,
51 | arch,
52 | prune: true,
53 | overwrite: true,
54 | all: shouldBuildAll,
55 | out: `app-builds`
56 | });
57 |
58 | console.log(opts)
59 | packager(opts, cb);
60 | }
61 |
--------------------------------------------------------------------------------
/web/src/app/pages/dashboard/dashboard.component.ts:
--------------------------------------------------------------------------------
1 | import {Component, OnInit }from '@angular/core';
2 |
3 |
4 | @Component( {
5 | selector:'app-dashboard',
6 | templateUrl:'./dashboard.component.html',
7 | styleUrls:['./dashboard.component.scss'],
8 | })
9 |
10 | export class DashboardComponent implements OnInit {
11 | public dashboard:any;
12 | public expanded:boolean = false;
13 |
14 | constructor() {
15 | }
16 |
17 | ngOnInit() {
18 | this.resetTiles();
19 | }
20 |
21 | public expandTile(tile:any) {
22 | for(var i = 0; i< this.dashboard.tiles.length; i++) {
23 | if(this.dashboard.tiles[i].title === tile.title ) {
24 | this.dashboard.tiles[i].rows = 2;
25 | this.dashboard.tiles[i].columns = 3;
26 | this.expanded = true;
27 | } else {
28 | this.dashboard.tiles[i].rows = 0;
29 | this.dashboard.tiles[i].columns = 0;
30 | }
31 | }
32 | }
33 |
34 | public resetTiles() {
35 | this.expanded = false;
36 | this.dashboard = {tiles:[ {
37 | title:'Trade History:',
38 | subTitle:'Trade History',
39 | content:'',
40 | columns:1,
41 | rows:2,
42 | }, {
43 | title:'Price History:',
44 | subTitle:'Price History',
45 | content:'',
46 | columns:2,
47 | rows:1,
48 | }, {
49 | title:'My Orders:',
50 | subTitle:'My Orders',
51 | content:'',
52 | columns:1,
53 | rows:1,
54 | }, {
55 | title:'Orders:',
56 | subTitle:'Orders',
57 | content:'',
58 | columns:1,
59 | rows:1,
60 | },
61 | ]};
62 | }
63 | }
64 |
65 |
66 |
--------------------------------------------------------------------------------
/web/src/app/services/theme-storage/theme-storage.service.spec.ts:
--------------------------------------------------------------------------------
1 | import {ThemeStorageService} from './theme-storage.service';
2 |
3 |
4 | const testStorageKey = ThemeStorageService.storageKey;
5 | const testTheme = {
6 | primary: '#000000',
7 | accent: '#ffffff',
8 | href: 'test/path/to/theme'
9 | };
10 | const createTestData = () => {
11 | window.localStorage[testStorageKey] = JSON.stringify(testTheme);
12 | };
13 | const clearTestData = () => {
14 | window.localStorage.clear();
15 | };
16 |
17 | describe('ThemeStorage Service', () => {
18 | const service = new ThemeStorageService();
19 | const getCurrTheme = () => JSON.parse(window.localStorage.getItem(testStorageKey));
20 | const secondTestTheme = {
21 | primary: '#666666',
22 | accent: '#333333',
23 | href: 'some/cool/path'
24 | };
25 |
26 | beforeEach(createTestData);
27 | afterEach(clearTestData);
28 |
29 | it('should set the current theme', () => {
30 | expect(getCurrTheme()).toEqual(testTheme);
31 | service.storeTheme(secondTestTheme);
32 | expect(getCurrTheme()).toEqual(secondTestTheme);
33 | });
34 |
35 | it('should get the current theme', () => {
36 | const theme = service.getStoredTheme();
37 | expect(theme).toEqual(testTheme);
38 | });
39 |
40 | it('should clear the stored theme data', () => {
41 | expect(getCurrTheme()).not.toBeNull();
42 | service.clearStorage();
43 | expect(getCurrTheme()).toBeNull();
44 | });
45 |
46 | it('should emit an event when setTheme is called', () => {
47 | spyOn(service.onThemeUpdate, 'emit');
48 | service.storeTheme(secondTestTheme);
49 | expect(service.onThemeUpdate.emit).toHaveBeenCalled();
50 | expect(service.onThemeUpdate.emit).toHaveBeenCalledWith(secondTestTheme);
51 | });
52 | });
--------------------------------------------------------------------------------
/exchanges/alphapoint/alphapoint_websocket.go:
--------------------------------------------------------------------------------
1 | package alphapoint
2 |
3 | import (
4 | "log"
5 | "net/http"
6 |
7 | "github.com/gorilla/websocket"
8 | "github.com/thrasher-/gocryptotrader/common"
9 | )
10 |
11 | const (
12 | alphapointDefaultWebsocketURL = "wss://sim3.alphapoint.com:8401/v1/GetTicker/"
13 | )
14 |
15 | // WebsocketClient starts a new webstocket connection
16 | func (a *Alphapoint) WebsocketClient() {
17 | for a.Enabled && a.Websocket {
18 | var Dialer websocket.Dialer
19 | var err error
20 | a.WebsocketConn, _, err = Dialer.Dial(a.WebsocketURL, http.Header{})
21 |
22 | if err != nil {
23 | log.Printf("%s Unable to connect to Websocket. Error: %s\n", a.Name, err)
24 | continue
25 | }
26 |
27 | if a.Verbose {
28 | log.Printf("%s Connected to Websocket.\n", a.Name)
29 | }
30 |
31 | err = a.WebsocketConn.WriteMessage(websocket.TextMessage, []byte(`{"messageType": "logon"}`))
32 |
33 | if err != nil {
34 | log.Println(err)
35 | return
36 | }
37 |
38 | for a.Enabled && a.Websocket {
39 | msgType, resp, err := a.WebsocketConn.ReadMessage()
40 | if err != nil {
41 | log.Println(err)
42 | break
43 | }
44 |
45 | switch msgType {
46 | case websocket.TextMessage:
47 | type MsgType struct {
48 | MessageType string `json:"messageType"`
49 | }
50 |
51 | msgType := MsgType{}
52 | err := common.JSONDecode(resp, &msgType)
53 | if err != nil {
54 | log.Println(err)
55 | continue
56 | }
57 |
58 | switch msgType.MessageType {
59 | case "Ticker":
60 | ticker := WebsocketTicker{}
61 | err = common.JSONDecode(resp, &ticker)
62 | if err != nil {
63 | log.Println(err)
64 | continue
65 | }
66 | }
67 | }
68 | }
69 | a.WebsocketConn.Close()
70 | log.Printf("%s Websocket client disconnected.", a.Name)
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/exchanges/localbitcoins/localbitcoins_test.go:
--------------------------------------------------------------------------------
1 | package localbitcoins
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/thrasher-/gocryptotrader/config"
7 | )
8 |
9 | var l LocalBitcoins
10 |
11 | // Please supply your own APIKEYS here for due diligence testing
12 |
13 | const (
14 | apiKey = ""
15 | apiSecret = ""
16 | )
17 |
18 | func TestSetDefaults(t *testing.T) {
19 | l.SetDefaults()
20 | }
21 |
22 | func TestSetup(t *testing.T) {
23 | cfg := config.GetConfig()
24 | cfg.LoadConfig("../../testdata/configtest.json")
25 | localbitcoinsConfig, err := cfg.GetExchangeConfig("LocalBitcoins")
26 | if err != nil {
27 | t.Error("Test Failed - LakeBTC Setup() init error")
28 | }
29 |
30 | localbitcoinsConfig.AuthenticatedAPISupport = true
31 | localbitcoinsConfig.APIKey = apiKey
32 | localbitcoinsConfig.APISecret = apiSecret
33 |
34 | l.Setup(localbitcoinsConfig)
35 | }
36 |
37 | func TestGetFee(t *testing.T) {
38 | t.Parallel()
39 | if l.GetFee(false) != 0 || l.GetFee(true) != 0 {
40 | t.Error("Test Failed - GetFee() error")
41 | }
42 | }
43 |
44 | func TestGetAccountInfo(t *testing.T) {
45 | t.Parallel()
46 | _, err := l.GetAccountInfo("", true)
47 | if err == nil {
48 | t.Error("Test Failed - GetAccountInfo() error", err)
49 | }
50 | _, err = l.GetAccountInfo("bitcoinbaron", false)
51 | if err != nil {
52 | t.Error("Test Failed - GetAccountInfo() error", err)
53 | }
54 | }
55 |
56 | func TestGetads(t *testing.T) {
57 | t.Parallel()
58 | _, err := l.Getads("")
59 | if err == nil {
60 | t.Error("Test Failed - Getads() - Full list, error", err)
61 | }
62 | _, err = l.Getads("1337")
63 | if err == nil {
64 | t.Error("Test Failed - Getads() error", err)
65 | }
66 | }
67 |
68 | func TestEditAd(t *testing.T) {
69 | t.Parallel()
70 | edit := AdEdit{}
71 | err := l.EditAd(edit, "1337")
72 | if err == nil {
73 | t.Error("Test Failed - EditAd() error", err)
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/web/src/app/app-routing.module.ts:
--------------------------------------------------------------------------------
1 | import { HomeComponent } from './pages/home/home.component';
2 | import { SettingsComponent } from './pages/settings/settings.component';
3 | import { AboutComponent } from './pages/about/about.component';
4 | import { DashboardComponent } from './pages/dashboard/dashboard.component';
5 | import { WalletComponent } from './pages/wallet/wallet.component';
6 | import { DonateComponent } from './pages/donate/donate.component';
7 | import { HistoryComponent } from './pages/history/history.component';
8 | import { TradingComponent } from './pages/trading/trading.component';
9 | import { ExchangeGridComponent } from './pages/exchange-grid/exchange-grid.component';
10 | import { CurrencyListComponent } from './pages/currency-list/currency-list.component';
11 |
12 | import { NgModule } from '@angular/core';
13 | import { Routes, RouterModule } from '@angular/router';
14 |
15 | const routes: Routes = [
16 | {
17 | path: '',
18 | component: HomeComponent
19 | },
20 | {
21 | path:'about',
22 | component: AboutComponent
23 | },
24 | {
25 | path:'dashboard',
26 | component: DashboardComponent
27 | },
28 | {
29 | path: 'settings',
30 | component: SettingsComponent
31 | },
32 | {
33 | path: 'wallet',
34 | component: WalletComponent
35 | }
36 | ,
37 | {
38 | path: 'donate',
39 | component: DonateComponent
40 | },
41 | {
42 | path: 'history',
43 | component: HistoryComponent
44 | },
45 | {
46 | path: 'trading',
47 | component: TradingComponent
48 | },
49 | {
50 | path: 'exchange-grid',
51 | component: ExchangeGridComponent
52 | },
53 | {
54 | path: 'currency-list',
55 | component: CurrencyListComponent
56 | }
57 |
58 | ];
59 |
60 | @NgModule({
61 | imports: [RouterModule.forRoot(routes, {useHash: true})],
62 | exports: [RouterModule]
63 | })
64 | export class AppRoutingModule { }
65 |
--------------------------------------------------------------------------------
/web/main.ts:
--------------------------------------------------------------------------------
1 | import { app, BrowserWindow, screen } from 'electron';
2 | import * as path from 'path';
3 |
4 |
5 | let win, serve;
6 | const args = process.argv.slice(1);
7 | serve = args.some(val => val === '--serve');
8 |
9 | if (serve) {
10 | require('electron-reload')(__dirname, {
11 | });
12 | }
13 |
14 | function createWindow() {
15 |
16 | const electronScreen = screen;
17 | const size = electronScreen.getPrimaryDisplay().workAreaSize;
18 |
19 | // Create the browser window.
20 | win = new BrowserWindow({
21 | x: 0,
22 | y: 0,
23 | width: size.width,
24 | height: size.height
25 | });
26 |
27 | // and load the index.html of the app.
28 | win.loadURL('file://' + __dirname + '/index.html');
29 |
30 | // Open the DevTools.
31 | if (serve) {
32 | win.webContents.openDevTools();
33 | }
34 |
35 | // Emitted when the window is closed.
36 | win.on('closed', () => {
37 | // Dereference the window object, usually you would store window
38 | // in an array if your app supports multi windows, this is the time
39 | // when you should delete the corresponding element.
40 | win = null;
41 | });
42 | }
43 |
44 | try {
45 |
46 | // This method will be called when Electron has finished
47 | // initialization and is ready to create browser windows.
48 | // Some APIs can only be used after this event occurs.
49 | app.on('ready', createWindow);
50 |
51 | // Quit when all windows are closed.
52 | app.on('window-all-closed', () => {
53 | // On OS X it is common for applications and their menu bar
54 | // to stay active until the user quits explicitly with Cmd + Q
55 | if (process.platform !== 'darwin') {
56 | app.quit();
57 | }
58 | });
59 |
60 | app.on('activate', () => {
61 | // On OS X it's common to re-create a window in the app when the
62 | // dock icon is clicked and there are no other windows open.
63 | if (win === null) {
64 | createWindow();
65 | }
66 | });
67 |
68 | } catch (e) {
69 | // Catch Error
70 | // throw e;
71 | }
72 |
--------------------------------------------------------------------------------
/web/src/app/services/style-manager/style-manager.service.spec.ts:
--------------------------------------------------------------------------------
1 | import {inject, TestBed} from '@angular/core/testing';
2 | import {HttpModule} from '@angular/http';
3 | import {StyleManagerComponent} from './style-manager.component';
4 |
5 |
6 | describe('StyleManager', () => {
7 | let styleManager: StyleManagerComponent;
8 |
9 | beforeEach(() => TestBed.configureTestingModule({
10 | imports: [HttpModule],
11 | providers: [StyleManagerComponent]
12 | }));
13 |
14 | beforeEach(inject([StyleManagerComponent], (sm: StyleManagerComponent) => {
15 | styleManager = sm;
16 | }));
17 |
18 | afterEach(() => {
19 | let links = document.head.querySelectorAll('link');
20 | for (let link of Array.prototype.slice.call(links)) {
21 | if (link.className.includes('style-manager-')) {
22 | document.head.removeChild(link);
23 | }
24 | }
25 | });
26 |
27 | it('should add stylesheet to head', () => {
28 | styleManager.setStyle('test', 'test.css');
29 | let styleEl = document.head.querySelector('.style-manager-test') as HTMLLinkElement;
30 | expect(styleEl).not.toBeNull();
31 | expect(styleEl.href.endsWith('test.css')).toBe(true);
32 | });
33 |
34 | it('should change existing stylesheet', () => {
35 | styleManager.setStyle('test', 'test.css');
36 | let styleEl = document.head.querySelector('.style-manager-test') as HTMLLinkElement;
37 | expect(styleEl).not.toBeNull();
38 | expect(styleEl.href.endsWith('test.css')).toBe(true);
39 |
40 | styleManager.setStyle('test', 'new.css');
41 | expect(styleEl.href.endsWith('new.css')).toBe(true);
42 | });
43 |
44 | it('should remove existing stylesheet', () => {
45 | styleManager.setStyle('test', 'test.css');
46 | let styleEl = document.head.querySelector('.style-manager-test') as HTMLLinkElement;
47 | expect(styleEl).not.toBeNull();
48 | expect(styleEl.href.endsWith('test.css')).toBe(true);
49 |
50 | styleManager.removeStyle('test');
51 | styleEl = document.head.querySelector('.style-manager-test') as HTMLLinkElement;
52 | expect(styleEl).toBeNull();
53 | });
54 | });
--------------------------------------------------------------------------------
/exchanges/nonce/nonce.go:
--------------------------------------------------------------------------------
1 | package nonce
2 |
3 | import (
4 | "strconv"
5 | "sync"
6 | "time"
7 | )
8 |
9 | // Nonce struct holds the nonce value
10 | type Nonce struct {
11 | // Standard nonce
12 | n int64
13 | mtx sync.Mutex
14 | // Hash table exclusive exchange specific nonce values
15 | boundedCall map[string]int64
16 | boundedMtx sync.Mutex
17 | }
18 |
19 | // Inc increments the nonce value
20 | func (n *Nonce) Inc() {
21 | n.mtx.Lock()
22 | n.n++
23 | n.mtx.Unlock()
24 | }
25 |
26 | // Get retrives the nonce value
27 | func (n *Nonce) Get() int64 {
28 | n.mtx.Lock()
29 | defer n.mtx.Unlock()
30 | return n.n
31 | }
32 |
33 | // GetInc increments and returns the value of the nonce
34 | func (n *Nonce) GetInc() int64 {
35 | n.mtx.Lock()
36 | defer n.mtx.Unlock()
37 | n.n++
38 | return n.n
39 | }
40 |
41 | // Set sets the nonce value
42 | func (n *Nonce) Set(val int64) {
43 | n.mtx.Lock()
44 | n.n = val
45 | n.mtx.Unlock()
46 | }
47 |
48 | // Returns a string version of the nonce
49 | func (n *Nonce) String() string {
50 | n.mtx.Lock()
51 | result := strconv.FormatInt(n.n, 10)
52 | n.mtx.Unlock()
53 | return result
54 | }
55 |
56 | // Value is a return type for GetValue
57 | type Value int64
58 |
59 | // GetValue returns a nonce value and can be set as a higher precision. Values
60 | // stored in an exchange specific hash table using a single locked call.
61 | func (n *Nonce) GetValue(exchName string, nanoPrecision bool) Value {
62 | n.boundedMtx.Lock()
63 | defer n.boundedMtx.Unlock()
64 |
65 | if n.boundedCall == nil {
66 | n.boundedCall = make(map[string]int64)
67 | }
68 |
69 | if n.boundedCall[exchName] == 0 {
70 | if nanoPrecision {
71 | n.boundedCall[exchName] = time.Now().UnixNano()
72 | return Value(n.boundedCall[exchName])
73 | }
74 | n.boundedCall[exchName] = time.Now().Unix()
75 | return Value(n.boundedCall[exchName])
76 | }
77 | n.boundedCall[exchName]++
78 | return Value(n.boundedCall[exchName])
79 | }
80 |
81 | // String is a Value method that changes format to a string
82 | func (v Value) String() string {
83 | return strconv.FormatInt(int64(v), 10)
84 | }
85 |
--------------------------------------------------------------------------------
/web/src/app/shared/theme-picker/theme-picker.ts:
--------------------------------------------------------------------------------
1 | import {Component, ViewEncapsulation, ChangeDetectionStrategy, NgModule} from '@angular/core';
2 | import { StyleManagerService } from './../../services/style-manager/style-manager.service';
3 |
4 | import { ThemeStorageService,DocsSiteTheme } from './../../services/theme-storage/theme-storage.service';
5 | import {CommonModule} from '@angular/common';
6 |
7 |
8 | @Component({
9 | selector: 'theme-picker',
10 | templateUrl: 'theme-picker.html',
11 | styleUrls: ['theme-picker.scss'],
12 | changeDetection: ChangeDetectionStrategy.OnPush,
13 | encapsulation: ViewEncapsulation.None,
14 | host: {'aria-hidden': 'true'},
15 | })
16 | export class ThemePickerComponent {
17 | currentTheme;
18 |
19 | themes = [
20 | {
21 | primary: '#673AB7',
22 | accent: '#FFC107',
23 | href: 'deeppurple-amber.css',
24 | isDark: false,
25 | },
26 | {
27 | primary: '#3F51B5',
28 | accent: '#E91E63',
29 | href: 'indigo-pink.css',
30 | isDark: false,
31 | isDefault: true,
32 | },
33 | {
34 | primary: '#E91E63',
35 | accent: '#607D8B',
36 | href: 'pink-bluegrey.css',
37 | isDark: true,
38 | },
39 | {
40 | primary: '#9C27B0',
41 | accent: '#4CAF50',
42 | href: 'purple-green.css',
43 | isDark: true,
44 | },
45 | ];
46 |
47 | constructor(
48 | public styleManager: StyleManagerService,
49 | private _themeStorage: ThemeStorageService
50 | ) {
51 | const currentTheme = this._themeStorage.getStoredTheme();
52 | if (currentTheme) {
53 | this.installTheme(currentTheme);
54 | }
55 | }
56 |
57 | installTheme(theme: DocsSiteTheme) {
58 | this.currentTheme = this._getCurrentThemeFromHref(theme.href);
59 |
60 | if (theme.isDefault) {
61 | this.styleManager.removeStyle('theme');
62 | } else {
63 | this.styleManager.setStyle('theme', `assets/${theme.href}`);
64 | }
65 |
66 | if (this.currentTheme) {
67 | this._themeStorage.storeTheme(this.currentTheme);
68 | }
69 | }
70 |
71 | private _getCurrentThemeFromHref(href: string): DocsSiteTheme {
72 | return this.themes.find(theme => theme.href === href);
73 | }
74 | }
--------------------------------------------------------------------------------
/exchanges/poloniex/poloniex_test.go:
--------------------------------------------------------------------------------
1 | package poloniex
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/thrasher-/gocryptotrader/config"
7 | )
8 |
9 | var p Poloniex
10 |
11 | // Please supply your own APIKEYS here for due diligence testing
12 |
13 | const (
14 | apiKey = ""
15 | apiSecret = ""
16 | )
17 |
18 | func TestSetDefaults(t *testing.T) {
19 | p.SetDefaults()
20 | }
21 |
22 | func TestSetup(t *testing.T) {
23 | cfg := config.GetConfig()
24 | cfg.LoadConfig("../../testdata/configtest.json")
25 | poloniexConfig, err := cfg.GetExchangeConfig("Poloniex")
26 | if err != nil {
27 | t.Error("Test Failed - Poloniex Setup() init error")
28 | }
29 |
30 | poloniexConfig.AuthenticatedAPISupport = true
31 | poloniexConfig.APIKey = apiKey
32 | poloniexConfig.APISecret = apiSecret
33 |
34 | p.Setup(poloniexConfig)
35 | }
36 |
37 | func TestGetFee(t *testing.T) {
38 | if p.GetFee() != 0 {
39 | t.Error("Test faild - Poloniex GetFee() error")
40 | }
41 | }
42 |
43 | func TestGetTicker(t *testing.T) {
44 | _, err := p.GetTicker()
45 | if err != nil {
46 | t.Error("Test faild - Poloniex GetTicker() error")
47 | }
48 | }
49 |
50 | func TestGetVolume(t *testing.T) {
51 | _, err := p.GetVolume()
52 | if err != nil {
53 | t.Error("Test faild - Poloniex GetVolume() error")
54 | }
55 | }
56 |
57 | func TestGetOrderbook(t *testing.T) {
58 | _, err := p.GetOrderbook("BTC_XMR", 50)
59 | if err != nil {
60 | t.Error("Test faild - Poloniex GetOrderbook() error", err)
61 | }
62 | }
63 |
64 | func TestGetTradeHistory(t *testing.T) {
65 | _, err := p.GetTradeHistory("BTC_XMR", "", "")
66 | if err != nil {
67 | t.Error("Test faild - Poloniex GetTradeHistory() error", err)
68 | }
69 | }
70 |
71 | func TestGetChartData(t *testing.T) {
72 | _, err := p.GetChartData("BTC_XMR", "1405699200", "1405699400", "300")
73 | if err != nil {
74 | t.Error("Test faild - Poloniex GetChartData() error", err)
75 | }
76 | }
77 |
78 | func TestGetCurrencies(t *testing.T) {
79 | _, err := p.GetCurrencies()
80 | if err != nil {
81 | t.Error("Test faild - Poloniex GetCurrencies() error", err)
82 | }
83 | }
84 |
85 | func TestGetLoanOrders(t *testing.T) {
86 | _, err := p.GetLoanOrders("BTC")
87 | if err != nil {
88 | t.Error("Test faild - Poloniex GetLoanOrders() error", err)
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/exchanges/bitstamp/bitstamp_websocket.go:
--------------------------------------------------------------------------------
1 | package bitstamp
2 |
3 | import (
4 | "log"
5 |
6 | "github.com/thrasher-/gocryptotrader/common"
7 | "github.com/toorop/go-pusher"
8 | )
9 |
10 | // PusherOrderbook holds order book information to be pushed
11 | type PusherOrderbook struct {
12 | Asks [][]string `json:"asks"`
13 | Bids [][]string `json:"bids"`
14 | }
15 |
16 | // PusherTrade holds trade information to be pushed
17 | type PusherTrade struct {
18 | Price float64 `json:"price"`
19 | Amount float64 `json:"amount"`
20 | ID int64 `json:"id"`
21 | }
22 |
23 | const (
24 | // BitstampPusherKey holds the current pusher key
25 | BitstampPusherKey = "de504dc5763aeef9ff52"
26 | )
27 |
28 | // PusherClient starts the push mechanism
29 | func (b *Bitstamp) PusherClient() {
30 | for b.Enabled && b.Websocket {
31 | pusherClient, err := pusher.NewClient(BitstampPusherKey)
32 | if err != nil {
33 | log.Printf("%s Unable to connect to Websocket. Error: %s\n", b.GetName(), err)
34 | continue
35 | }
36 |
37 | err = pusherClient.Subscribe("live_trades")
38 | if err != nil {
39 | log.Printf("%s Websocket Trade subscription error: %s\n", b.GetName(), err)
40 | }
41 |
42 | err = pusherClient.Subscribe("order_book")
43 | if err != nil {
44 | log.Printf("%s Websocket Trade subscription error: %s\n", b.GetName(), err)
45 | }
46 |
47 | dataChannelTrade, err := pusherClient.Bind("data")
48 | if err != nil {
49 | log.Printf("%s Websocket Bind error: %s\n", b.GetName(), err)
50 | continue
51 | }
52 | tradeChannelTrade, err := pusherClient.Bind("trade")
53 | if err != nil {
54 | log.Printf("%s Websocket Bind error: %s\n", b.GetName(), err)
55 | continue
56 | }
57 |
58 | log.Printf("%s Pusher client connected.\n", b.GetName())
59 |
60 | for b.Websocket {
61 | select {
62 | case data := <-dataChannelTrade:
63 | result := PusherOrderbook{}
64 | err := common.JSONDecode([]byte(data.Data), &result)
65 | if err != nil {
66 | log.Println(err)
67 | }
68 | case trade := <-tradeChannelTrade:
69 | result := PusherTrade{}
70 | err := common.JSONDecode([]byte(trade.Data), &result)
71 | if err != nil {
72 | log.Println(err)
73 | }
74 | log.Printf("%s Pusher trade: Price: %f Amount: %f\n", b.GetName(), result.Price, result.Amount)
75 | }
76 | }
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/exchanges/btcc/btcc_test.go:
--------------------------------------------------------------------------------
1 | package btcc
2 |
3 | import (
4 | "testing"
5 | "time"
6 |
7 | "github.com/thrasher-/gocryptotrader/config"
8 | )
9 |
10 | // Please supply your own APIkeys here to do better tests
11 | const (
12 | apiKey = ""
13 | apiSecret = ""
14 | )
15 |
16 | var b BTCC
17 |
18 | func TestSetDefaults(t *testing.T) {
19 | b.SetDefaults()
20 | }
21 |
22 | func TestSetup(t *testing.T) {
23 | t.Parallel()
24 | b.Name = "BTCC"
25 | cfg := config.GetConfig()
26 | cfg.LoadConfig("../../testdata/configtest.json")
27 | bConfig, err := cfg.GetExchangeConfig("BTCC")
28 | if err != nil {
29 | t.Error("Test Failed - BTCC Setup() init error")
30 | }
31 |
32 | b.SetDefaults()
33 | b.Setup(bConfig)
34 |
35 | if !b.IsEnabled() || b.AuthenticatedAPISupport || b.RESTPollingDelay != time.Duration(10) ||
36 | b.Verbose || b.Websocket || len(b.BaseCurrencies) < 1 ||
37 | len(b.AvailablePairs) < 1 || len(b.EnabledPairs) < 1 {
38 | t.Error("Test Failed - BTCC Setup values not set correctly")
39 | }
40 |
41 | bConfig.Enabled = false
42 | b.Setup(bConfig)
43 |
44 | if b.IsEnabled() {
45 | t.Error("Test failed - BTCC TestSetup incorrect value")
46 | }
47 | }
48 |
49 | func TestGetFee(t *testing.T) {
50 | if b.GetFee() != 0 {
51 | t.Error("Test failed - GetFee() error")
52 | }
53 | }
54 |
55 | func TestGetTicker(t *testing.T) {
56 | _, err := b.GetTicker("ltccny")
57 | if err == nil {
58 | t.Error("Test failed - GetTicker() error", err)
59 | }
60 | }
61 |
62 | func TestGetTradesLast24h(t *testing.T) {
63 | _, err := b.GetTradesLast24h("ltccny")
64 | if err != nil {
65 | t.Error("Test failed - GetTradesLast24h() error", err)
66 | }
67 | }
68 |
69 | func TestGetTradeHistory(t *testing.T) {
70 | _, err := b.GetTradeHistory("ltccny", 0, 0, time.Time{})
71 | if err != nil {
72 | t.Error("Test failed - GetTradeHistory() error", err)
73 | }
74 | }
75 |
76 | func TestGetOrderBook(t *testing.T) {
77 | b.Verbose = true
78 | _, err := b.GetOrderBook("ltccny", 100)
79 | if err == nil {
80 | t.Error("Test failed - GetOrderBook() error", err)
81 | }
82 | _, err = b.GetOrderBook("ltccny", 0)
83 | if err == nil {
84 | t.Error("Test failed - GetOrderBook() error", err)
85 | }
86 | }
87 |
88 | func TestGetAccountInfo(t *testing.T) {
89 | err := b.GetAccountInfo("")
90 | if err == nil {
91 | t.Error("Test failed - GetAccountInfo() error", err)
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/tools/config/config.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "flag"
5 | "log"
6 |
7 | "github.com/thrasher-/gocryptotrader/common"
8 | "github.com/thrasher-/gocryptotrader/config"
9 | )
10 |
11 | // EncryptOrDecrypt returns a string from a boolean
12 | func EncryptOrDecrypt(encrypt bool) string {
13 | if encrypt {
14 | return "encrypted"
15 | }
16 | return "decrypted"
17 | }
18 |
19 | func main() {
20 | var inFile, outFile, key string
21 | var encrypt bool
22 | var err error
23 | configFile := config.GetFilePath("")
24 | flag.StringVar(&inFile, "infile", configFile, "The config input file to process.")
25 | flag.StringVar(&outFile, "outfile", configFile+".out", "The config output file.")
26 | flag.BoolVar(&encrypt, "encrypt", true, "Wether to encrypt or decrypt.")
27 | flag.StringVar(&key, "key", "", "The key to use for AES encryption.")
28 | flag.Parse()
29 |
30 | log.Println("GoCryptoTrader: config-helper tool.")
31 |
32 | if key == "" {
33 | result, errf := config.PromptForConfigKey()
34 | if errf != nil {
35 | log.Fatal("Unable to obtain encryption/decryption key.")
36 | }
37 | key = string(result)
38 | }
39 |
40 | file, err := common.ReadFile(inFile)
41 | if err != nil {
42 | log.Fatalf("Unable to read input file %s. Error: %s.", inFile, err)
43 | }
44 |
45 | if config.ConfirmECS(file) && encrypt {
46 | log.Println("File is already encrypted. Decrypting..")
47 | encrypt = false
48 | }
49 |
50 | if !config.ConfirmECS(file) && !encrypt {
51 | var result interface{}
52 | errf := config.ConfirmConfigJSON(file, result)
53 | if errf != nil {
54 | log.Fatal("File isn't in JSON format")
55 | }
56 | log.Println("File is already decrypted. Encrypting..")
57 | encrypt = true
58 | }
59 |
60 | var data []byte
61 | if encrypt {
62 | data, err = config.EncryptConfigFile(file, []byte(key))
63 | if err != nil {
64 | log.Fatalf("Unable to encrypt config data. Error: %s.", err)
65 | }
66 | } else {
67 | data, err = config.DecryptConfigFile(file, []byte(key))
68 | if err != nil {
69 | log.Fatalf("Unable to decrypt config data. Error: %s.", err)
70 | }
71 | }
72 |
73 | err = common.WriteFile(outFile, data)
74 | if err != nil {
75 | log.Fatalf("Unable to write output file %s. Error: %s", outFile, err)
76 | }
77 | log.Printf(
78 | "Successfully %s input file %s and wrote output to %s.\n",
79 | EncryptOrDecrypt(encrypt), inFile, outFile,
80 | )
81 | }
82 |
--------------------------------------------------------------------------------
/web/src/app/app.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/currency/symbol/symbol.go:
--------------------------------------------------------------------------------
1 | package symbol
2 |
3 | import "errors"
4 |
5 | // symbols map holds the currency name and symbol mappings
6 | var symbols = map[string]string{
7 | "ALL": "Lek",
8 | "AFN": "؋",
9 | "ARS": "$",
10 | "AWG": "ƒ",
11 | "AUD": "$",
12 | "AZN": "ман",
13 | "BSD": "$",
14 | "BBD": "$",
15 | "BYN": "Br",
16 | "BZD": "BZ$",
17 | "BMD": "$",
18 | "BOB": "$b",
19 | "BAM": "KM",
20 | "BWP": "P",
21 | "BGN": "лв",
22 | "BRL": "R$",
23 | "BND": "$",
24 | "KHR": "៛",
25 | "CAD": "$",
26 | "KYD": "$",
27 | "CLP": "$",
28 | "CNY": "¥",
29 | "COP": "$",
30 | "CRC": "₡",
31 | "HRK": "kn",
32 | "CUP": "₱",
33 | "CZK": "Kč",
34 | "DKK": "kr",
35 | "DOP": "RD$",
36 | "XCD": "$",
37 | "EGP": "£",
38 | "SVC": "$",
39 | "EUR": "€",
40 | "FKP": "£",
41 | "FJD": "$",
42 | "GHS": "¢",
43 | "GIP": "£",
44 | "GTQ": "Q",
45 | "GGP": "£",
46 | "GYD": "$",
47 | "HNL": "L",
48 | "HKD": "$",
49 | "HUF": "Ft",
50 | "ISK": "kr",
51 | "INR": "₹",
52 | "IDR": "Rp",
53 | "IRR": "﷼",
54 | "IMP": "£",
55 | "ILS": "₪",
56 | "JMD": "J$",
57 | "JPY": "¥",
58 | "JEP": "£",
59 | "KZT": "лв",
60 | "KPW": "₩",
61 | "KRW": "₩",
62 | "KGS": "лв",
63 | "LAK": "₭",
64 | "LBP": "£",
65 | "LRD": "$",
66 | "MKD": "ден",
67 | "MYR": "RM",
68 | "MUR": "₨",
69 | "MXN": "$",
70 | "MNT": "₮",
71 | "MZN": "MT",
72 | "NAD": "$",
73 | "NPR": "₨",
74 | "ANG": "ƒ",
75 | "NZD": "$",
76 | "NIO": "C$",
77 | "NGN": "₦",
78 | "NOK": "kr",
79 | "OMR": "﷼",
80 | "PKR": "₨",
81 | "PAB": "B/.",
82 | "PYG": "Gs",
83 | "PEN": "S/.",
84 | "PHP": "₱",
85 | "PLN": "zł",
86 | "QAR": "﷼",
87 | "RON": "lei",
88 | "RUB": "₽",
89 | "SHP": "£",
90 | "SAR": "﷼",
91 | "RSD": "Дин.",
92 | "SCR": "₨",
93 | "SGD": "$",
94 | "SBD": "$",
95 | "SOS": "S",
96 | "ZAR": "R",
97 | "LKR": "₨",
98 | "SEK": "kr",
99 | "CHF": "CHF",
100 | "SRD": "$",
101 | "SYP": "£",
102 | "TWD": "NT$",
103 | "THB": "฿",
104 | "TTD": "TT$",
105 | "TRY": "₺",
106 | "TVD": "$",
107 | "UAH": "₴",
108 | "GBP": "£",
109 | "USD": "$",
110 | "UYU": "$U",
111 | "UZS": "лв",
112 | "VEF": "Bs",
113 | "VND": "₫",
114 | "YER": "﷼",
115 | "ZWD": "Z$",
116 | }
117 |
118 | // GetSymbolByCurrencyName returns a currency symbol
119 | func GetSymbolByCurrencyName(currency string) (string, error) {
120 | result, ok := symbols[currency]
121 | if !ok {
122 | return "", errors.New("currency symbol not found")
123 | }
124 | return result, nil
125 | }
126 |
--------------------------------------------------------------------------------
/web/src/app/pages/exchange-grid/exchange-grid.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Poloniex
6 |
7 |
8 |
9 |
10 | image and blurb
11 |
30 |
31 |
32 |
33 | Kraken
34 |
35 |
36 |
37 |
38 | image and blurb
39 |
59 |
60 |
--------------------------------------------------------------------------------
/exchanges/anx/anx_types.go:
--------------------------------------------------------------------------------
1 | package anx
2 |
3 | type ANXOrder struct {
4 | OrderType string `json:"orderType"`
5 | BuyTradedCurrency bool `json:"buyTradedCurrency"`
6 | TradedCurrency string `json:"tradedCurrency"`
7 | SettlementCurrency string `json:"settlementCurrency"`
8 | TradedCurrencyAmount string `json:"tradedCurrencyAmount"`
9 | SettlementCurrencyAmount string `json:"settlementCurrencyAmount"`
10 | LimitPriceInSettlementCurrency string `json:"limitPriceInSettlementCurrency"`
11 | ReplaceExistingOrderUUID string `json:"replaceExistingOrderUuid"`
12 | ReplaceOnlyIfActive bool `json:"replaceOnlyIfActive"`
13 | }
14 |
15 | type ANXOrderResponse struct {
16 | BuyTradedCurrency bool `json:"buyTradedCurrency"`
17 | ExecutedAverageRate string `json:"executedAverageRate"`
18 | LimitPriceInSettlementCurrency string `json:"limitPriceInSettlementCurrency"`
19 | OrderID string `json:"orderId"`
20 | OrderStatus string `json:"orderStatus"`
21 | OrderType string `json:"orderType"`
22 | ReplaceExistingOrderUUID string `json:"replaceExistingOrderId"`
23 | SettlementCurrency string `json:"settlementCurrency"`
24 | SettlementCurrencyAmount string `json:"settlementCurrencyAmount"`
25 | SettlementCurrencyOutstanding string `json:"settlementCurrencyOutstanding"`
26 | Timestamp int64 `json:"timestamp"`
27 | TradedCurrency string `json:"tradedCurrency"`
28 | TradedCurrencyAmount string `json:"tradedCurrencyAmount"`
29 | TradedCurrencyOutstanding string `json:"tradedCurrencyOutstanding"`
30 | }
31 |
32 | type ANXTickerComponent struct {
33 | Currency string `json:"currency"`
34 | Display string `json:"display"`
35 | DisplayShort string `json:"display_short"`
36 | Value string `json:"value"`
37 | }
38 |
39 | type ANXTicker struct {
40 | Result string `json:"result"`
41 | Data struct {
42 | High ANXTickerComponent `json:"high"`
43 | Low ANXTickerComponent `json:"low"`
44 | Avg ANXTickerComponent `json:"avg"`
45 | Vwap ANXTickerComponent `json:"vwap"`
46 | Vol ANXTickerComponent `json:"vol"`
47 | Last ANXTickerComponent `json:"last"`
48 | Buy ANXTickerComponent `json:"buy"`
49 | Sell ANXTickerComponent `json:"sell"`
50 | Now string `json:"now"`
51 | UpdateTime string `json:"dataUpdateTime"`
52 | } `json:"data"`
53 | }
54 |
--------------------------------------------------------------------------------
/exchanges/nonce/nonce_test.go:
--------------------------------------------------------------------------------
1 | package nonce
2 |
3 | import (
4 | "strconv"
5 | "testing"
6 | "time"
7 | )
8 |
9 | func TestInc(t *testing.T) {
10 | var nonce Nonce
11 | nonce.Set(1)
12 | nonce.Inc()
13 | expected := int64(2)
14 | result := nonce.Get()
15 | if result != expected {
16 | t.Errorf("Test failed. Expected %d got %d", expected, result)
17 | }
18 | }
19 |
20 | func TestGet(t *testing.T) {
21 | var nonce Nonce
22 | nonce.Set(112321313)
23 | expected := int64(112321313)
24 | result := nonce.Get()
25 | if expected != result {
26 | t.Errorf("Test failed. Expected %d got %d", expected, result)
27 | }
28 | }
29 |
30 | func TestGetInc(t *testing.T) {
31 | var nonce Nonce
32 | nonce.Set(1)
33 | expected := int64(2)
34 | result := nonce.GetInc()
35 | if expected != result {
36 | t.Errorf("Test failed. Expected %d got %d", expected, result)
37 | }
38 | }
39 |
40 | func TestSet(t *testing.T) {
41 | var nonce Nonce
42 | nonce.Set(1)
43 | expected := int64(1)
44 | result := nonce.Get()
45 | if expected != result {
46 | t.Errorf("Test failed. Expected %d got %d", expected, result)
47 | }
48 | }
49 |
50 | func TestString(t *testing.T) {
51 | var nonce Nonce
52 | nonce.Set(12312313131)
53 | expected := "12312313131"
54 | result := nonce.String()
55 | if expected != result {
56 | t.Errorf("Test failed. Expected %s got %s", expected, result)
57 | }
58 | }
59 |
60 | func TestGetValue(t *testing.T) {
61 | var nonce Nonce
62 | timeNowNano := strconv.FormatInt(time.Now().UnixNano(), 10)
63 | time.Sleep(time.Millisecond * 100)
64 | nValue := nonce.GetValue("dingdong", true).String()
65 |
66 | if timeNowNano == nValue {
67 | t.Error("Test failed - GetValue() error, incorrect values")
68 | }
69 |
70 | if len(nValue) != 19 {
71 | t.Error("Test failed - GetValue() error, incorrect values")
72 | }
73 |
74 | timeNowUnix := nonce.GetValue("dongding", false)
75 | if len(timeNowUnix.String()) != 10 {
76 | t.Error("Test failed - GetValue() error, incorrect values")
77 | }
78 |
79 | n := nonce.GetValue("dongding", false)
80 | if n != timeNowUnix+1 {
81 | t.Error("Test failed - GetValue() error, incorrect values")
82 | }
83 | }
84 |
85 | func TestNonceConcurrency(t *testing.T) {
86 | var nonce Nonce
87 | nonce.Set(12312)
88 |
89 | for i := 0; i < 1000; i++ {
90 | go nonce.Inc()
91 | }
92 |
93 | // Allow sufficient time for all routines to finish
94 | time.Sleep(time.Second)
95 |
96 | result := nonce.Get()
97 | expected := int64(12312 + 1000)
98 | if expected != result {
99 | t.Errorf("Test failed. Expected %d got %d", expected, result)
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/web/src/polyfills.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * This file includes polyfills needed by Angular and is loaded before the app.
3 | * You can add your own extra polyfills to this file.
4 | *
5 | * This file is divided into 2 sections:
6 | * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers.
7 | * 2. Application imports. Files imported after ZoneJS that should be loaded before your main
8 | * file.
9 | *
10 | * The current setup is for so-called "evergreen" browsers; the last versions of browsers that
11 | * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera),
12 | * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile.
13 | *
14 | * Learn more in https://angular.io/docs/ts/latest/guide/browser-support.html
15 | */
16 |
17 | /***************************************************************************************************
18 | * BROWSER POLYFILLS
19 | */
20 |
21 | /** IE9, IE10 and IE11 requires all of the following polyfills. **/
22 | // import 'core-js/es6/symbol';
23 | // import 'core-js/es6/object';
24 | // import 'core-js/es6/function';
25 | // import 'core-js/es6/parse-int';
26 | // import 'core-js/es6/parse-float';
27 | // import 'core-js/es6/number';
28 | // import 'core-js/es6/math';
29 | // import 'core-js/es6/string';
30 | // import 'core-js/es6/date';
31 | // import 'core-js/es6/array';
32 | // import 'core-js/es6/regexp';
33 | // import 'core-js/es6/map';
34 | // import 'core-js/es6/set';
35 |
36 | /** IE10 and IE11 requires the following for NgClass support on SVG elements */
37 | // import 'classlist.js'; // Run `npm install --save classlist.js`.
38 |
39 | /** IE10 and IE11 requires the following to support `@angular/animation`. */
40 | // import 'web-animations-js'; // Run `npm install --save web-animations-js`.
41 |
42 |
43 | /** Evergreen browsers require these. **/
44 | import 'core-js/es6/reflect';
45 | import 'core-js/es7/reflect';
46 |
47 |
48 | /** ALL Firefox browsers require the following to support `@angular/animation`. **/
49 | // import 'web-animations-js'; // Run `npm install --save web-animations-js`.
50 |
51 |
52 |
53 | /***************************************************************************************************
54 | * Zone JS is required by Angular itself.
55 | */
56 | import 'zone.js/dist/zone-mix'; // Included with Angular CLI.
57 |
58 |
59 | /***************************************************************************************************
60 | * APPLICATION IMPORTS
61 | */
62 |
63 | /**
64 | * Date, currency, decimal and percent pipes.
65 | * Needed for: All but Chrome, Firefox, Edge, IE11 and Safari 10
66 | */
67 | // import 'intl'; // Run `npm install --save intl`.
68 |
--------------------------------------------------------------------------------
/web/src/app/shared/all-enabled-currency-tickers/all-enabled-currency-tickers.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit } from '@angular/core';
2 | import { WebsocketHandlerService } from './../../services/websocket-handler/websocket-handler.service';
3 |
4 | @Component({
5 | selector: 'app-all-enabled-currency-tickers',
6 | templateUrl: './all-enabled-currency-tickers.component.html',
7 | styleUrls: ['./all-enabled-currency-tickers.component.scss']
8 | })
9 | export class AllEnabledCurrencyTickersComponent implements OnInit {
10 | private ws: WebsocketHandlerService;
11 | allCurrencies:ExchangeCurrency[];
12 | tickerCards: TickerUpdate[];
13 |
14 | constructor(private websocketHandler: WebsocketHandlerService) {
15 | this.ws = websocketHandler;
16 | this.allCurrencies = [];
17 | this.tickerCards = [];
18 | this.ws.messages.subscribe(msg => {
19 | if (msg.Event === 'ticker_update') {
20 | var modal = {};
21 | modal.currencyPair = msg.data.CurrencyPair;
22 | modal.exchangeName = msg.Exchange;
23 | var found = false;
24 |
25 | for(var i = 0; i< this.allCurrencies.length; i++) {
26 | if(this.allCurrencies[i].currencyPair === msg.data.CurrencyPair &&
27 | this.allCurrencies[i].exchangeName === msg.Exchange) {
28 | found = true;
29 | }
30 | }
31 | if(!found) {
32 | //time to add
33 | var ticker = msg.data;
34 | ticker.Exchange = msg.Exchange;
35 | this.tickerCards.push(ticker);
36 | this.allCurrencies.push(modal);
37 | } else {
38 | //time to replace
39 | for(var j = 0; j< this.tickerCards.length; j++) {
40 | if(this.tickerCards[j].Exchange === msg.Exchange
41 | && this.tickerCards[j].CurrencyPair === msg.data.CurrencyPair) {
42 | var ticker = msg.data;
43 | this.tickerCards[j] = ticker;
44 | this.tickerCards[j].Exchange = msg.Exchange;
45 | return;
46 | }
47 | }
48 | }
49 | }
50 | });
51 | }
52 | ngOnInit() { }
53 | }
54 |
55 | export interface ExchangeCurrency {
56 | currencyPair: string;
57 | exchangeName:string;
58 | }
59 |
60 | export interface CurrencyPair {
61 | delimiter: string;
62 | first_currency: string;
63 | second_currency: string;
64 | }
65 |
66 | export interface TickerUpdate {
67 | Pair: CurrencyPair;
68 | CurrencyPair: string;
69 | Last: number;
70 | High: number;
71 | Low: number;
72 | Bid: number;
73 | Ask: number;
74 | Volume: number;
75 | PriceATH: number;
76 | Exchange:string;
77 | }
--------------------------------------------------------------------------------
/web/README.md:
--------------------------------------------------------------------------------
1 | # GoCryptoTrader Website
2 |
3 |
4 |
5 | A website interface to interact with the main GoCryptoTrader application. It is developed with Angular 4 with support for Electron
6 |
7 | ## This is still in active development
8 |
9 | You can track ideas, planned features and what's in progresss on this Trello board: [https://trello.com/b/ZAhMhpOy/gocryptotrader](https://trello.com/b/ZAhMhpOy/gocryptotrader).
10 |
11 | ## Current Features
12 |
13 | + It can run
14 | + It can be compiled with Electron to run as an executable
15 | + Websocket support to listen to GoCryptoTrader events
16 | + Material design
17 | + Has a semi-working Settings page
18 | + Has a basic ticker dashboard
19 |
20 | ## Install dependencies with npm
21 |
22 | ``` bash
23 | npm install
24 | ```
25 |
26 | If you want to generate Angular components with Angular-cli , you **MUST** install `@angular/cli` in npm global context.
27 | Please follow [Angular-cli documentation](https://github.com/angular/angular-cli) if you had installed a previous version of `angular-cli`.
28 |
29 | ``` bash
30 | npm install -g @angular/cli
31 | ```
32 |
33 | ## To build for development
34 |
35 | ``` bash
36 | npm run start:web
37 | ```
38 |
39 | Voila! You can use GoCryptoTrader web app in a local development environment with webpack watching!
40 |
41 | ## To build for production
42 |
43 | + Using development variables (environments/index.ts) : `npm run electron:dev`
44 | + Using production variables (environments/index.prod.ts) : `npm run electron:prod`
45 |
46 | Your built files are in the /dist folder.
47 |
48 | ## Included Commands
49 |
50 | |Command|Description|
51 | |--|--|
52 | |`npm run start:web`| Execute the app in the brower |
53 | |`npm run electron:linux`| Builds your application and creates an app consumable on linux system |
54 | |`npm run electron:windows`| On a Windows OS, builds your application and creates an app consumable in windows 32/64 bit systems |
55 | |`npm run electron:mac`| On a MAC OS, builds your application and generates a `.app` file of your application that can be run on Ma |
56 |
57 | ## Execute E2E tests
58 |
59 | You can find end-to-end tests in /e2e folder.
60 |
61 | You can run tests with the command lines below:
62 |
63 | + **in a terminal window** -> First, start a web server on port 4200 : `npm run start:web`
64 | + **in another terminal window** -> Then, launch Protractor (E2E framework): `npm run e2e`
65 |
66 | ## Contributors
67 |
68 | |User|Github|Contribution|
69 | |--|--|--|
70 | |GloriousCode|https://github.com/gloriouscode |Lead front-end|
71 | |Maxime GRIS|https://github.com/maximegris |Angular4 + Electron Base|
72 | |Shazbert|https://github.com/shazbert |Initial designs|
--------------------------------------------------------------------------------
/config/config_encryption_test.go:
--------------------------------------------------------------------------------
1 | package config
2 |
3 | import (
4 | "reflect"
5 | "testing"
6 |
7 | "github.com/thrasher-/gocryptotrader/common"
8 | )
9 |
10 | func TestPromptForConfigEncryption(t *testing.T) {
11 | t.Parallel()
12 |
13 | if Cfg.PromptForConfigEncryption() {
14 | t.Error("Test failed. PromptForConfigEncryption return incorrect bool")
15 | }
16 | }
17 |
18 | func TestPromptForConfigKey(t *testing.T) {
19 | t.Parallel()
20 |
21 | byteyBite, err := PromptForConfigKey()
22 | if err == nil && len(byteyBite) > 1 {
23 | t.Errorf("Test failed. PromptForConfigKey: %s", err)
24 | }
25 | }
26 |
27 | func TestEncryptDecryptConfigFile(t *testing.T) { //Dual function Test
28 | testKey := []byte("12345678901234567890123456789012")
29 |
30 | testConfigData, err := common.ReadFile(ConfigTestFile)
31 | if err != nil {
32 | t.Errorf("Test failed. EncryptConfigFile: %s", err)
33 | }
34 | encryptedFile, err2 := EncryptConfigFile(testConfigData, testKey)
35 | if err2 != nil {
36 | t.Errorf("Test failed. EncryptConfigFile: %s", err2)
37 | }
38 | if reflect.TypeOf(encryptedFile).String() != "[]uint8" {
39 | t.Errorf("Test failed. EncryptConfigFile: Incorrect Type")
40 | }
41 |
42 | decryptedFile, err3 := DecryptConfigFile(encryptedFile, testKey)
43 | if err3 != nil {
44 | t.Errorf("Test failed. DecryptConfigFile: %s", err3)
45 | }
46 | if reflect.TypeOf(decryptedFile).String() != "[]uint8" {
47 | t.Errorf("Test failed. DecryptConfigFile: Incorrect Type")
48 | }
49 | // unmarshalled := Config{} // racecondition
50 | // err4 := json.Unmarshal(decryptedFile, &unmarshalled)
51 | // if err4 != nil {
52 | // t.Errorf("Test failed. DecryptConfigFile: %s", err3)
53 | // }
54 | }
55 |
56 | func TestConfirmConfigJSON(t *testing.T) {
57 | var result interface{}
58 | testConfirmJSON, err := common.ReadFile(ConfigTestFile)
59 | if err != nil {
60 | t.Errorf("Test failed. testConfirmJSON: %s", err)
61 | }
62 |
63 | err2 := ConfirmConfigJSON(testConfirmJSON, &result)
64 | if err2 != nil {
65 | t.Errorf("Test failed. testConfirmJSON: %s", err2)
66 | }
67 | if result == nil {
68 | t.Errorf("Test failed. testConfirmJSON: Error Unmarshalling JSON")
69 | }
70 | err3 := ConfirmConfigJSON(testConfirmJSON, result)
71 | if err3 == nil {
72 | t.Errorf("Test failed. testConfirmJSON: %s", err3)
73 | }
74 | }
75 |
76 | func TestConfirmECS(t *testing.T) {
77 | t.Parallel()
78 |
79 | ECStest := []byte(EncryptConfirmString)
80 | if !ConfirmECS(ECStest) {
81 | t.Errorf("Test failed. TestConfirmECS: Error finding ECS.")
82 | }
83 | }
84 |
85 | func TestRemoveECS(t *testing.T) {
86 | t.Parallel()
87 |
88 | ECStest := []byte(EncryptConfirmString)
89 | isremoved := RemoveECS(ECStest)
90 |
91 | if string(isremoved) != "" {
92 | t.Errorf("Test failed. TestConfirmECS: Error ECS not deleted.")
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/exchanges/kraken/kraken_types.go:
--------------------------------------------------------------------------------
1 | package kraken
2 |
3 | // GeneralResponse is a generalized response type
4 | type GeneralResponse struct {
5 | Result map[string]interface{} `json:"result"`
6 | Error []interface{} `json:"error"`
7 | }
8 |
9 | // AssetPairs holds asset pair information
10 | type AssetPairs struct {
11 | Altname string `json:"altname"`
12 | AclassBase string `json:"aclass_base"`
13 | Base string `json:"base"`
14 | AclassQuote string `json:"aclass_quote"`
15 | Quote string `json:"quote"`
16 | Lot string `json:"lot"`
17 | PairDecimals int `json:"pair_decimals"`
18 | LotDecimals int `json:"lot_decimals"`
19 | LotMultiplier int `json:"lot_multiplier"`
20 | LeverageBuy []int `json:"leverage_buy"`
21 | LeverageSell []int `json:"leverage_sell"`
22 | Fees [][]float64 `json:"fees"`
23 | FeesMaker [][]float64 `json:"fees_maker"`
24 | FeeVolumeCurrency string `json:"fee_volume_currency"`
25 | MarginCall int `json:"margin_call"`
26 | MarginStop int `json:"margin_stop"`
27 | }
28 |
29 | // Ticker is a standard ticker type
30 | type Ticker struct {
31 | Ask float64
32 | Bid float64
33 | Last float64
34 | Volume float64
35 | VWAP float64
36 | Trades int64
37 | Low float64
38 | High float64
39 | Open float64
40 | }
41 |
42 | // TickerResponse holds ticker information before its put into the Ticker struct
43 | type TickerResponse struct {
44 | Ask []string `json:"a"`
45 | Bid []string `json:"b"`
46 | Last []string `json:"c"`
47 | Volume []string `json:"v"`
48 | VWAP []string `json:"p"`
49 | Trades []int64 `json:"t"`
50 | Low []string `json:"l"`
51 | High []string `json:"h"`
52 | Open string `json:"o"`
53 | }
54 |
55 | // OpenHighLowClose contains ticker event information
56 | type OpenHighLowClose struct {
57 | Time float64
58 | Open float64
59 | High float64
60 | Low float64
61 | Close float64
62 | Vwap float64
63 | Volume float64
64 | Count float64
65 | }
66 |
67 | // RecentTrades holds recent trade data
68 | type RecentTrades struct {
69 | Price float64
70 | Volume float64
71 | Time float64
72 | BuyOrSell string
73 | MarketOrLimit string
74 | Miscellaneous interface{}
75 | }
76 |
77 | // OrderbookBase stores the orderbook price and amount data
78 | type OrderbookBase struct {
79 | Price float64
80 | Amount float64
81 | }
82 |
83 | // Orderbook stores the bids and asks orderbook data
84 | type Orderbook struct {
85 | Bids []OrderbookBase
86 | Asks []OrderbookBase
87 | }
88 |
89 | // Spread holds the spread between trades
90 | type Spread struct {
91 | Time float64
92 | Bid float64
93 | Ask float64
94 | }
95 |
--------------------------------------------------------------------------------
/web/src/app/pages/wallet/wallet.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit } from '@angular/core';
2 | import { WebsocketHandlerService } from './../../services/websocket-handler/websocket-handler.service';
3 | import { Wallet, CoinTotal } from './../../shared/classes/wallet';
4 | import {Sort} from '@angular/material';
5 |
6 | @Component({
7 | selector: 'app-wallet',
8 | templateUrl: './wallet.component.html',
9 | styleUrls: ['./wallet.component.scss']
10 | })
11 |
12 | export class WalletComponent implements OnInit {
13 | private ws: WebsocketHandlerService;
14 | private failCount = 0;
15 | private timer: any;
16 | public wallet: Wallet;
17 | displayedColumns = ['coin', 'balance'];
18 |
19 | private getWalletMessage = {
20 | Event: 'GetPortfolio',
21 | data: null,
22 | };
23 |
24 | constructor(private websocketHandler: WebsocketHandlerService) {
25 | this.wallet= null;
26 | this.ws = websocketHandler;
27 | this.ws.messages.subscribe(msg => {
28 | if (msg.Event === 'GetPortfolio') {
29 | console.log(JSON.stringify(msg.data));
30 | this.wallet = msg.data;
31 |
32 | this.attachIcon(this.wallet.coin_totals);
33 | this.attachIcon(this.wallet.coins_offline);
34 | this.attachIcon(this.wallet.coins_online);
35 |
36 | this.attachIcon(this.wallet.offline_summary.BTC);
37 | this.attachIcon(this.wallet.offline_summary.ETH);
38 | this.attachIcon(this.wallet.offline_summary.LTC);
39 |
40 | this.attachIcon(this.wallet.online_summary.BTC);
41 | this.attachIcon(this.wallet.online_summary.ETH);
42 | this.attachIcon(this.wallet.online_summary.LTC);
43 | }
44 | });
45 | }
46 |
47 | public coinIcon(coin:string) :string {
48 | switch(coin) {
49 | case "BTC": return "attach_money";
50 | case "LTC": return "attach_money";
51 | case "ETH": return "attach_money";
52 | }
53 | }
54 |
55 | public attachIcon(items: CoinTotal[]): void {
56 | if (items) {
57 | for (var i = 0; i < items.length; i++) {
58 | items[i].icon = this.coinIcon(items[i].coin);
59 | }
60 | }
61 | }
62 |
63 | ngOnInit() {
64 | this.setWallet();
65 | }
66 |
67 | //there has to be a better way
68 | private resendMessageIfPageRefreshed(): void {
69 | if (this.failCount <= 10) {
70 | setTimeout(() => {
71 | if (this.wallet === null || this.wallet === undefined) {
72 | this.failCount++;
73 | this.setWallet();
74 | }
75 | }, 1000);
76 | } else {
77 | console.log('Could not load wallet. Check if GocryptoTrader server is running, otherwise open a ticket');
78 | }
79 | }
80 |
81 | private setWallet():void {
82 | this.ws.messages.next(this.getWalletMessage);
83 | this.resendMessageIfPageRefreshed();
84 | }
85 | }
86 |
87 |
88 |
--------------------------------------------------------------------------------
/exchanges/bitfinex/bitfinex_websocket_test.go:
--------------------------------------------------------------------------------
1 | package bitfinex
2 |
3 | import (
4 | "net/http"
5 | "testing"
6 |
7 | "github.com/gorilla/websocket"
8 | )
9 |
10 | func TestWebsocketPingHandler(t *testing.T) {
11 | wsPingHandler := Bitfinex{}
12 | var Dialer websocket.Dialer
13 | var err error
14 |
15 | wsPingHandler.WebsocketConn, _, err = Dialer.Dial(bitfinexWebsocket, http.Header{})
16 | if err != nil {
17 | t.Errorf("Test Failed - Bitfinex dialer error: %s", err)
18 | }
19 | err = wsPingHandler.WebsocketPingHandler()
20 | if err != nil {
21 | t.Errorf("Test Failed - Bitfinex WebsocketPingHandler() error: %s", err)
22 | }
23 | err = wsPingHandler.WebsocketConn.Close()
24 | if err != nil {
25 | t.Errorf("Test Failed - Bitfinex websocketConn.Close() error: %s", err)
26 | }
27 | }
28 |
29 | func TestWebsocketSubscribe(t *testing.T) {
30 | websocketSubcribe := Bitfinex{}
31 | var Dialer websocket.Dialer
32 | var err error
33 | params := make(map[string]string)
34 | params["pair"] = "BTCUSD"
35 |
36 | websocketSubcribe.WebsocketConn, _, err = Dialer.Dial(bitfinexWebsocket, http.Header{})
37 | if err != nil {
38 | t.Errorf("Test Failed - Bitfinex Dialer error: %s", err)
39 | }
40 | err = websocketSubcribe.WebsocketSubscribe("ticker", params)
41 | if err != nil {
42 | t.Errorf("Test Failed - Bitfinex WebsocketSubscribe() error: %s", err)
43 | }
44 |
45 | err = websocketSubcribe.WebsocketConn.Close()
46 | if err != nil {
47 | t.Errorf("Test Failed - Bitfinex websocketConn.Close() error: %s", err)
48 | }
49 | }
50 |
51 | func TestWebsocketSendAuth(t *testing.T) {
52 | wsSendAuth := Bitfinex{}
53 | var Dialer websocket.Dialer
54 | var err error
55 |
56 | wsSendAuth.WebsocketConn, _, err = Dialer.Dial(bitfinexWebsocket, http.Header{})
57 | if err != nil {
58 | t.Errorf("Test Failed - Bitfinex Dialer error: %s", err)
59 | }
60 | err = wsSendAuth.WebsocketSendAuth()
61 | if err != nil {
62 | t.Errorf("Test Failed - Bitfinex WebsocketSendAuth() error: %s", err)
63 | }
64 | }
65 |
66 | func TestWebsocketAddSubscriptionChannel(t *testing.T) {
67 | wsAddSubscriptionChannel := Bitfinex{}
68 | wsAddSubscriptionChannel.SetDefaults()
69 | var Dialer websocket.Dialer
70 | var err error
71 |
72 | wsAddSubscriptionChannel.WebsocketConn, _, err = Dialer.Dial(bitfinexWebsocket, http.Header{})
73 | if err != nil {
74 | t.Errorf("Test Failed - Bitfinex Dialer error: %s", err)
75 | }
76 |
77 | wsAddSubscriptionChannel.WebsocketAddSubscriptionChannel(1337, "ticker", "BTCUSD")
78 | if len(wsAddSubscriptionChannel.WebsocketSubdChannels) == 0 {
79 | t.Errorf("Test Failed - Bitfinex WebsocketAddSubscriptionChannel() error: %s", err)
80 | }
81 | if wsAddSubscriptionChannel.WebsocketSubdChannels[1337].Channel != "ticker" {
82 | t.Errorf("Test Failed - Bitfinex WebsocketAddSubscriptionChannel() error: %s", err)
83 | }
84 | if wsAddSubscriptionChannel.WebsocketSubdChannels[1337].Pair != "BTCUSD" {
85 | t.Errorf("Test Failed - Bitfinex WebsocketAddSubscriptionChannel() error: %s", err)
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/exchanges/lakebtc/lakebtc_test.go:
--------------------------------------------------------------------------------
1 | package lakebtc
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/thrasher-/gocryptotrader/config"
7 | )
8 |
9 | var l LakeBTC
10 |
11 | // Please add your own APIkeys to do correct due diligence testing.
12 | const (
13 | apiKey = ""
14 | apiSecret = ""
15 | )
16 |
17 | func TestSetDefaults(t *testing.T) {
18 | l.SetDefaults()
19 | }
20 |
21 | func TestSetup(t *testing.T) {
22 | cfg := config.GetConfig()
23 | cfg.LoadConfig("../../testdata/configtest.json")
24 | lakebtcConfig, err := cfg.GetExchangeConfig("LakeBTC")
25 | if err != nil {
26 | t.Error("Test Failed - LakeBTC Setup() init error")
27 | }
28 |
29 | lakebtcConfig.AuthenticatedAPISupport = true
30 | lakebtcConfig.APIKey = apiKey
31 | lakebtcConfig.APISecret = apiSecret
32 |
33 | l.Setup(lakebtcConfig)
34 | }
35 |
36 | func TestGetFee(t *testing.T) {
37 | t.Parallel()
38 | if l.GetFee(false) != 0.2 {
39 | t.Error("Test Failed - GetFee() error")
40 | }
41 | if l.GetFee(true) != 0.15 {
42 | t.Error("Test Failed - GetFee() error")
43 | }
44 | }
45 |
46 | func TestGetTicker(t *testing.T) {
47 | t.Parallel()
48 | _, err := l.GetTicker()
49 | if err != nil {
50 | t.Error("Test Failed - GetTicker() error", err)
51 | }
52 | }
53 |
54 | func TestGetOrderBook(t *testing.T) {
55 | t.Parallel()
56 | _, err := l.GetOrderBook("BTCUSD")
57 | if err != nil {
58 | t.Error("Test Failed - GetOrderBook() error", err)
59 | }
60 | }
61 |
62 | func TestGetTradeHistory(t *testing.T) {
63 | t.Parallel()
64 | _, err := l.GetTradeHistory("BTCUSD")
65 | if err != nil {
66 | t.Error("Test Failed - GetTradeHistory() error", err)
67 | }
68 | }
69 |
70 | func TestTrade(t *testing.T) {
71 | t.Parallel()
72 | _, err := l.Trade(0, 0, 0, "USD")
73 | if err == nil {
74 | t.Error("Test Failed - Trade() error", err)
75 | }
76 | }
77 |
78 | func TestGetOpenOrders(t *testing.T) {
79 | t.Parallel()
80 | _, err := l.GetOpenOrders()
81 | if err == nil {
82 | t.Error("Test Failed - GetOpenOrders() error", err)
83 | }
84 | }
85 |
86 | func TestGetOrders(t *testing.T) {
87 | t.Parallel()
88 | _, err := l.GetOrders([]int64{1, 2})
89 | if err == nil {
90 | t.Error("Test Failed - GetOrders() error", err)
91 | }
92 | }
93 |
94 | func TestCancelOrder(t *testing.T) {
95 | t.Parallel()
96 | err := l.CancelOrder(1337)
97 | if err == nil {
98 | t.Error("Test Failed - CancelOrder() error", err)
99 | }
100 | }
101 |
102 | func TestGetTrades(t *testing.T) {
103 | t.Parallel()
104 | _, err := l.GetTrades(1337)
105 | if err == nil {
106 | t.Error("Test Failed - GetTrades() error", err)
107 | }
108 | }
109 |
110 | func TestGetExternalAccounts(t *testing.T) {
111 | t.Parallel()
112 | _, err := l.GetExternalAccounts()
113 | if err == nil {
114 | t.Error("Test Failed - GetExternalAccounts() error", err)
115 | }
116 | }
117 |
118 | func TestCreateWithdraw(t *testing.T) {
119 | t.Parallel()
120 | _, err := l.CreateWithdraw(0, 1337)
121 | if err == nil {
122 | t.Error("Test Failed - CreateWithdraw() error", err)
123 | }
124 | }
125 |
--------------------------------------------------------------------------------
/restful_router.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "log"
6 | "net/http"
7 | "time"
8 |
9 | "github.com/gorilla/mux"
10 | "github.com/thrasher-/gocryptotrader/exchanges"
11 | )
12 |
13 | // RESTLogger logs the requests internally
14 | func RESTLogger(inner http.Handler, name string) http.Handler {
15 | return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
16 | start := time.Now()
17 |
18 | inner.ServeHTTP(w, r)
19 |
20 | log.Printf(
21 | "%s\t%s\t%s\t%s",
22 | r.Method,
23 | r.RequestURI,
24 | name,
25 | time.Since(start),
26 | )
27 | })
28 | }
29 |
30 | // Route is a sub type that holds the request routes
31 | type Route struct {
32 | Name string
33 | Method string
34 | Pattern string
35 | HandlerFunc http.HandlerFunc
36 | }
37 |
38 | // Routes is an array of all the registered routes
39 | type Routes []Route
40 |
41 | var routes = Routes{}
42 |
43 | // NewRouter takes in the exchange interfaces and returns a new multiplexor
44 | // router
45 | func NewRouter(exchanges []exchange.IBotExchange) *mux.Router {
46 | router := mux.NewRouter().StrictSlash(true)
47 |
48 | routes = Routes{
49 | Route{
50 | "",
51 | "GET",
52 | "/",
53 | getIndex,
54 | },
55 | Route{
56 | "GetAllSettings",
57 | "GET",
58 | "/config/all",
59 | RESTGetAllSettings,
60 | },
61 | Route{
62 | "SaveAllSettings",
63 | "POST",
64 | "/config/all/save",
65 | RESTSaveAllSettings,
66 | },
67 | Route{
68 | "AllEnabledAccountInfo",
69 | "GET",
70 | "/exchanges/enabled/accounts/all",
71 | RESTGetAllEnabledAccountInfo,
72 | },
73 | Route{
74 | "AllActiveExchangesAndCurrencies",
75 | "GET",
76 | "/exchanges/enabled/latest/all",
77 | RESTGetAllActiveTickers,
78 | },
79 | Route{
80 | "IndividualExchangeAndCurrency",
81 | "GET",
82 | "/exchanges/{exchangeName}/latest/{currency}",
83 | RESTGetTicker,
84 | },
85 | Route{
86 | "GetPortfolio",
87 | "GET",
88 | "/portfolio/all",
89 | RESTGetPortfolio,
90 | },
91 | Route{
92 | "AllActiveExchangesAndOrderbooks",
93 | "GET",
94 | "/exchanges/orderbook/latest/all",
95 | RESTGetAllActiveOrderbooks,
96 | },
97 | Route{
98 | "IndividualExchangeOrderbook",
99 | "GET",
100 | "/exchanges/{exchangeName}/orderbook/latest/{currency}",
101 | RESTGetOrderbook,
102 | },
103 | Route{
104 | "ws",
105 | "GET",
106 | "/ws",
107 | WebsocketClientHandler,
108 | },
109 | }
110 |
111 | for _, route := range routes {
112 | var handler http.Handler
113 | handler = route.HandlerFunc
114 | handler = RESTLogger(handler, route.Name)
115 |
116 | router.
117 | Methods(route.Method).
118 | Path(route.Pattern).
119 | Name(route.Name).
120 | Handler(handler)
121 | }
122 | return router
123 | }
124 |
125 | func getIndex(w http.ResponseWriter, r *http.Request) {
126 | fmt.Fprint(w, "GoCryptoTrader RESTful interface. For the web GUI, please visit the web GUI readme.")
127 | w.WriteHeader(http.StatusOK)
128 | }
129 |
--------------------------------------------------------------------------------
/exchanges/liqui/liqui_test.go:
--------------------------------------------------------------------------------
1 | package liqui
2 |
3 | import (
4 | "net/url"
5 | "testing"
6 |
7 | "github.com/thrasher-/gocryptotrader/config"
8 | )
9 |
10 | var l Liqui
11 |
12 | const (
13 | apiKey = ""
14 | apiSecret = ""
15 | )
16 |
17 | func TestSetDefaults(t *testing.T) {
18 | l.SetDefaults()
19 | }
20 |
21 | func TestSetup(t *testing.T) {
22 | cfg := config.GetConfig()
23 | cfg.LoadConfig("../../testdata/configtest.json")
24 | liquiConfig, err := cfg.GetExchangeConfig("Liqui")
25 | if err != nil {
26 | t.Error("Test Failed - liqui Setup() init error")
27 | }
28 |
29 | liquiConfig.AuthenticatedAPISupport = true
30 | liquiConfig.APIKey = apiKey
31 | liquiConfig.APISecret = apiSecret
32 |
33 | l.Setup(liquiConfig)
34 | }
35 |
36 | func TestGetFee(t *testing.T) {
37 | _, err := l.GetFee("usd")
38 | if err == nil {
39 | t.Error("Test Failed - liqui GetFee() error", err)
40 | }
41 | }
42 |
43 | func TestGetAvailablePairs(t *testing.T) {
44 | v := l.GetAvailablePairs(false)
45 | if len(v) != 0 {
46 | t.Error("Test Failed - liqui GetFee() error")
47 | }
48 | }
49 |
50 | func TestGetInfo(t *testing.T) {
51 | _, err := l.GetInfo()
52 | if err != nil {
53 | t.Error("Test Failed - liqui GetInfo() error", err)
54 | }
55 | }
56 |
57 | func TestGetTicker(t *testing.T) {
58 | _, err := l.GetTicker("eth_btc")
59 | if err != nil {
60 | t.Error("Test Failed - liqui GetTicker() error", err)
61 | }
62 | }
63 |
64 | func TestGetDepth(t *testing.T) {
65 | _, err := l.GetDepth("eth_btc")
66 | if err != nil {
67 | t.Error("Test Failed - liqui GetDepth() error", err)
68 | }
69 | }
70 |
71 | func TestGetTrades(t *testing.T) {
72 | _, err := l.GetTrades("eth_btc")
73 | if err != nil {
74 | t.Error("Test Failed - liqui GetTrades() error", err)
75 | }
76 | }
77 |
78 | func TestGetAccountInfo(t *testing.T) {
79 | _, err := l.GetAccountInfo()
80 | if err == nil {
81 | t.Error("Test Failed - liqui GetAccountInfo() error", err)
82 | }
83 | }
84 |
85 | func TestTrade(t *testing.T) {
86 | _, err := l.Trade("", "", 0, 1)
87 | if err == nil {
88 | t.Error("Test Failed - liqui Trade() error", err)
89 | }
90 | }
91 |
92 | func TestGetActiveOrders(t *testing.T) {
93 | _, err := l.GetActiveOrders("eth_btc")
94 | if err == nil {
95 | t.Error("Test Failed - liqui GetActiveOrders() error", err)
96 | }
97 | }
98 |
99 | func TestGetOrderInfo(t *testing.T) {
100 | _, err := l.GetOrderInfo(1337)
101 | if err == nil {
102 | t.Error("Test Failed - liqui GetOrderInfo() error", err)
103 | }
104 | }
105 |
106 | func TestCancelOrder(t *testing.T) {
107 | _, err := l.CancelOrder(1337)
108 | if err == nil {
109 | t.Error("Test Failed - liqui CancelOrder() error", err)
110 | }
111 | }
112 |
113 | func TestGetTradeHistory(t *testing.T) {
114 | _, err := l.GetTradeHistory(url.Values{}, "")
115 | if err == nil {
116 | t.Error("Test Failed - liqui GetTradeHistory() error", err)
117 | }
118 | }
119 |
120 | func TestWithdrawCoins(t *testing.T) {
121 | _, err := l.WithdrawCoins("btc", 1337, "someaddr")
122 | if err == nil {
123 | t.Error("Test Failed - liqui WithdrawCoins() error", err)
124 | }
125 | }
126 |
--------------------------------------------------------------------------------
/exchanges/gdax/gdax_websocket.go:
--------------------------------------------------------------------------------
1 | package gdax
2 |
3 | import (
4 | "log"
5 | "net/http"
6 |
7 | "github.com/gorilla/websocket"
8 | "github.com/thrasher-/gocryptotrader/common"
9 | )
10 |
11 | const (
12 | GDAX_WEBSOCKET_URL = "wss://ws-feed.gdax.com"
13 | )
14 |
15 | func (g *GDAX) WebsocketSubscribe(product string, conn *websocket.Conn) error {
16 | subscribe := WebsocketSubscribe{"subscribe", product}
17 | json, err := common.JSONEncode(subscribe)
18 | if err != nil {
19 | return err
20 | }
21 |
22 | err = conn.WriteMessage(websocket.TextMessage, json)
23 |
24 | if err != nil {
25 | return err
26 | }
27 | return nil
28 | }
29 |
30 | func (g *GDAX) WebsocketClient() {
31 | for g.Enabled && g.Websocket {
32 | var Dialer websocket.Dialer
33 | conn, _, err := Dialer.Dial(GDAX_WEBSOCKET_URL, http.Header{})
34 |
35 | if err != nil {
36 | log.Printf("%s Unable to connect to Websocket. Error: %s\n", g.GetName(), err)
37 | continue
38 | }
39 |
40 | log.Printf("%s Connected to Websocket.\n", g.GetName())
41 |
42 | currencies := []string{}
43 | for _, x := range g.EnabledPairs {
44 | currency := x[0:3] + "-" + x[3:]
45 | currencies = append(currencies, currency)
46 | }
47 |
48 | for _, x := range currencies {
49 | err = g.WebsocketSubscribe(x, conn)
50 | if err != nil {
51 | log.Printf("%s Websocket subscription error: %s\n", g.GetName(), err)
52 | continue
53 | }
54 | }
55 |
56 | if g.Verbose {
57 | log.Printf("%s Subscribed to product messages.", g.GetName())
58 | }
59 |
60 | for g.Enabled && g.Websocket {
61 | msgType, resp, err := conn.ReadMessage()
62 | if err != nil {
63 | log.Println(err)
64 | break
65 | }
66 |
67 | switch msgType {
68 | case websocket.TextMessage:
69 | type MsgType struct {
70 | Type string `json:"type"`
71 | }
72 |
73 | msgType := MsgType{}
74 | err := common.JSONDecode(resp, &msgType)
75 | if err != nil {
76 | log.Println(err)
77 | continue
78 | }
79 |
80 | switch msgType.Type {
81 | case "error":
82 | log.Println(string(resp))
83 | break
84 | case "received":
85 | received := WebsocketReceived{}
86 | err := common.JSONDecode(resp, &received)
87 | if err != nil {
88 | log.Println(err)
89 | continue
90 | }
91 | case "open":
92 | open := WebsocketOpen{}
93 | err := common.JSONDecode(resp, &open)
94 | if err != nil {
95 | log.Println(err)
96 | continue
97 | }
98 | case "done":
99 | done := WebsocketDone{}
100 | err := common.JSONDecode(resp, &done)
101 | if err != nil {
102 | log.Println(err)
103 | continue
104 | }
105 | case "match":
106 | match := WebsocketMatch{}
107 | err := common.JSONDecode(resp, &match)
108 | if err != nil {
109 | log.Println(err)
110 | continue
111 | }
112 | case "change":
113 | change := WebsocketChange{}
114 | err := common.JSONDecode(resp, &change)
115 | if err != nil {
116 | log.Println(err)
117 | continue
118 | }
119 | }
120 | }
121 | }
122 | conn.Close()
123 | log.Printf("%s Websocket client disconnected.", g.GetName())
124 | }
125 | }
126 |
--------------------------------------------------------------------------------
/web/tslint.json:
--------------------------------------------------------------------------------
1 | {
2 | "rulesDirectory": [
3 | "node_modules/codelyzer"
4 | ],
5 | "rules": {
6 | "callable-types": true,
7 | "class-name": true,
8 | "comment-format": [
9 | true,
10 | "check-space"
11 | ],
12 | "curly": true,
13 | "eofline": true,
14 | "forin": true,
15 | "import-blacklist": [true, "rxjs"],
16 | "import-spacing": true,
17 | "indent": [
18 | true,
19 | "spaces"
20 | ],
21 | "interface-over-type-literal": true,
22 | "label-position": true,
23 | "max-line-length": [
24 | true,
25 | 140
26 | ],
27 | "member-access": false,
28 | "member-ordering": [
29 | true,
30 | "static-before-instance",
31 | "variables-before-functions"
32 | ],
33 | "no-arg": true,
34 | "no-bitwise": true,
35 | "no-console": [
36 | true,
37 | "debug",
38 | "info",
39 | "time",
40 | "timeEnd",
41 | "trace"
42 | ],
43 | "no-construct": true,
44 | "no-debugger": true,
45 | "no-duplicate-variable": true,
46 | "no-empty": false,
47 | "no-empty-interface": true,
48 | "no-eval": true,
49 | "no-inferrable-types": [true, "ignore-params"],
50 | "no-shadowed-variable": true,
51 | "no-string-literal": false,
52 | "no-string-throw": true,
53 | "no-switch-case-fall-through": true,
54 | "no-trailing-whitespace": true,
55 | "no-unused-expression": true,
56 | "no-use-before-declare": true,
57 | "no-var-keyword": true,
58 | "object-literal-sort-keys": false,
59 | "one-line": [
60 | true,
61 | "check-open-brace",
62 | "check-catch",
63 | "check-else",
64 | "check-whitespace"
65 | ],
66 | "prefer-const": true,
67 | "quotemark": [
68 | true,
69 | "single"
70 | ],
71 | "radix": true,
72 | "semicolon": [
73 | "always"
74 | ],
75 | "triple-equals": [
76 | true,
77 | "allow-null-check"
78 | ],
79 | "typedef-whitespace": [
80 | true,
81 | {
82 | "call-signature": "nospace",
83 | "index-signature": "nospace",
84 | "parameter": "nospace",
85 | "property-declaration": "nospace",
86 | "variable-declaration": "nospace"
87 | }
88 | ],
89 | "typeof-compare": true,
90 | "unified-signatures": true,
91 | "variable-name": false,
92 | "whitespace": [
93 | true,
94 | "check-branch",
95 | "check-decl",
96 | "check-operator",
97 | "check-separator",
98 | "check-type"
99 | ],
100 |
101 | "directive-selector": [true, "attribute", "app", "camelCase"],
102 | "component-selector": [true, "element", "app", "kebab-case"],
103 | "use-input-property-decorator": true,
104 | "use-output-property-decorator": true,
105 | "use-host-property-decorator": true,
106 | "no-input-rename": true,
107 | "no-output-rename": true,
108 | "use-life-cycle-interface": true,
109 | "use-pipe-transform-interface": true,
110 | "component-class-suffix": true,
111 | "directive-class-suffix": true,
112 | "no-access-missing-member": true,
113 | "templates-use-public": true,
114 | "invoke-injectable": true
115 | }
116 | }
117 |
--------------------------------------------------------------------------------
/exchanges/alphapoint/alphapoint_wrapper.go:
--------------------------------------------------------------------------------
1 | package alphapoint
2 |
3 | import (
4 | "github.com/thrasher-/gocryptotrader/currency/pair"
5 | "github.com/thrasher-/gocryptotrader/exchanges"
6 | "github.com/thrasher-/gocryptotrader/exchanges/orderbook"
7 | "github.com/thrasher-/gocryptotrader/exchanges/ticker"
8 | )
9 |
10 | // GetExchangeAccountInfo retrieves balances for all enabled currencies on the
11 | // Alphapoint exchange
12 | func (a *Alphapoint) GetExchangeAccountInfo() (exchange.AccountInfo, error) {
13 | var response exchange.AccountInfo
14 | response.ExchangeName = a.GetName()
15 | account, err := a.GetAccountInfo()
16 | if err != nil {
17 | return response, err
18 | }
19 | for i := 0; i < len(account.Currencies); i++ {
20 | var exchangeCurrency exchange.AccountCurrencyInfo
21 | exchangeCurrency.CurrencyName = account.Currencies[i].Name
22 | exchangeCurrency.TotalValue = float64(account.Currencies[i].Balance)
23 | exchangeCurrency.Hold = float64(account.Currencies[i].Hold)
24 |
25 | response.Currencies = append(response.Currencies, exchangeCurrency)
26 | }
27 | //If it all works out
28 | return response, nil
29 | }
30 |
31 | // UpdateTicker updates and returns the ticker for a currency pair
32 | func (a *Alphapoint) UpdateTicker(p pair.CurrencyPair, assetType string) (ticker.Price, error) {
33 | var tickerPrice ticker.Price
34 | tick, err := a.GetTicker(p.Pair().String())
35 | if err != nil {
36 | return tickerPrice, err
37 | }
38 |
39 | tickerPrice.Pair = p
40 | tickerPrice.Ask = tick.Ask
41 | tickerPrice.Bid = tick.Bid
42 | tickerPrice.Low = tick.Low
43 | tickerPrice.High = tick.High
44 | tickerPrice.Volume = tick.Volume
45 | tickerPrice.Last = tick.Last
46 | ticker.ProcessTicker(a.GetName(), p, tickerPrice, assetType)
47 | return ticker.GetTicker(a.Name, p, assetType)
48 | }
49 |
50 | // GetTickerPrice returns the ticker for a currency pair
51 | func (a *Alphapoint) GetTickerPrice(p pair.CurrencyPair, assetType string) (ticker.Price, error) {
52 | tick, err := ticker.GetTicker(a.GetName(), p, assetType)
53 | if err != nil {
54 | return a.UpdateTicker(p, assetType)
55 | }
56 | return tick, nil
57 | }
58 |
59 | // UpdateOrderbook updates and returns the orderbook for a currency pair
60 | func (a *Alphapoint) UpdateOrderbook(p pair.CurrencyPair, assetType string) (orderbook.Base, error) {
61 | var orderBook orderbook.Base
62 | orderbookNew, err := a.GetOrderbook(p.Pair().String())
63 | if err != nil {
64 | return orderBook, err
65 | }
66 |
67 | for x := range orderbookNew.Bids {
68 | data := orderbookNew.Bids[x]
69 | orderBook.Bids = append(orderBook.Bids, orderbook.Item{Amount: data.Quantity, Price: data.Price})
70 | }
71 |
72 | for x := range orderbookNew.Asks {
73 | data := orderbookNew.Asks[x]
74 | orderBook.Asks = append(orderBook.Asks, orderbook.Item{Amount: data.Quantity, Price: data.Price})
75 | }
76 |
77 | orderbook.ProcessOrderbook(a.GetName(), p, orderBook, assetType)
78 | return orderbook.GetOrderbook(a.Name, p, assetType)
79 | }
80 |
81 | // GetOrderbookEx returns the orderbook for a currency pair
82 | func (a *Alphapoint) GetOrderbookEx(p pair.CurrencyPair, assetType string) (orderbook.Base, error) {
83 | ob, err := orderbook.GetOrderbook(a.GetName(), p, assetType)
84 | if err == nil {
85 | return a.UpdateOrderbook(p, assetType)
86 | }
87 | return ob, nil
88 | }
89 |
--------------------------------------------------------------------------------
/exchanges/btcc/btcc_websocket.go:
--------------------------------------------------------------------------------
1 | package btcc
2 |
3 | import (
4 | "fmt"
5 | "log"
6 |
7 | "github.com/thrasher-/gocryptotrader/common"
8 | "github.com/thrasher-/socketio"
9 | )
10 |
11 | const (
12 | BTCC_SOCKETIO_ADDRESS = "https://websocket.btcc.com"
13 | )
14 |
15 | var BTCCSocket *socketio.SocketIO
16 |
17 | func (b *BTCC) OnConnect(output chan socketio.Message) {
18 | if b.Verbose {
19 | log.Printf("%s Connected to Websocket.", b.GetName())
20 | }
21 |
22 | currencies := []string{}
23 | for _, x := range b.EnabledPairs {
24 | currency := common.StringToLower(x[3:] + x[0:3])
25 | currencies = append(currencies, currency)
26 | }
27 | endpoints := []string{"marketdata", "grouporder"}
28 |
29 | for _, x := range endpoints {
30 | for _, y := range currencies {
31 | channel := fmt.Sprintf(`"%s_%s"`, x, y)
32 | if b.Verbose {
33 | log.Printf("%s Websocket subscribing to channel: %s.", b.GetName(), channel)
34 | }
35 | output <- socketio.CreateMessageEvent("subscribe", channel, b.OnMessage, BTCCSocket.Version)
36 | }
37 | }
38 | }
39 |
40 | func (b *BTCC) OnDisconnect(output chan socketio.Message) {
41 | log.Printf("%s Disconnected from websocket server.. Reconnecting.\n", b.GetName())
42 | b.WebsocketClient()
43 | }
44 |
45 | func (b *BTCC) OnError() {
46 | log.Printf("%s Error with Websocket connection.. Reconnecting.\n", b.GetName())
47 | b.WebsocketClient()
48 | }
49 |
50 | func (b *BTCC) OnMessage(message []byte, output chan socketio.Message) {
51 | if b.Verbose {
52 | log.Printf("%s Websocket message received which isn't handled by default.\n", b.GetName())
53 | log.Println(string(message))
54 | }
55 | }
56 |
57 | func (b *BTCC) OnTicker(message []byte, output chan socketio.Message) {
58 | type Response struct {
59 | Ticker WebsocketTicker `json:"ticker"`
60 | }
61 | var resp Response
62 | err := common.JSONDecode(message, &resp)
63 |
64 | if err != nil {
65 | log.Println(err)
66 | return
67 | }
68 | }
69 |
70 | func (b *BTCC) OnGroupOrder(message []byte, output chan socketio.Message) {
71 | type Response struct {
72 | GroupOrder WebsocketGroupOrder `json:"grouporder"`
73 | }
74 | var resp Response
75 | err := common.JSONDecode(message, &resp)
76 |
77 | if err != nil {
78 | log.Println(err)
79 | return
80 | }
81 | }
82 |
83 | func (b *BTCC) OnTrade(message []byte, output chan socketio.Message) {
84 | trade := WebsocketTrade{}
85 | err := common.JSONDecode(message, &trade)
86 |
87 | if err != nil {
88 | log.Println(err)
89 | return
90 | }
91 | }
92 |
93 | func (b *BTCC) WebsocketClient() {
94 | events := make(map[string]func(message []byte, output chan socketio.Message))
95 | events["grouporder"] = b.OnGroupOrder
96 | events["ticker"] = b.OnTicker
97 | events["trade"] = b.OnTrade
98 |
99 | BTCCSocket = &socketio.SocketIO{
100 | Version: 1,
101 | OnConnect: b.OnConnect,
102 | OnEvent: events,
103 | OnError: b.OnError,
104 | OnMessage: b.OnMessage,
105 | OnDisconnect: b.OnDisconnect,
106 | }
107 |
108 | for b.Enabled && b.Websocket {
109 | err := socketio.ConnectToSocket(BTCC_SOCKETIO_ADDRESS, BTCCSocket)
110 | if err != nil {
111 | log.Printf("%s Unable to connect to Websocket. Err: %s\n", b.GetName(), err)
112 | continue
113 | }
114 | log.Printf("%s Disconnected from Websocket.\n", b.GetName())
115 | }
116 | }
117 |
--------------------------------------------------------------------------------
/exchanges/huobi/huobi_wrapper.go:
--------------------------------------------------------------------------------
1 | package huobi
2 |
3 | import (
4 | "log"
5 |
6 | "github.com/thrasher-/gocryptotrader/common"
7 | "github.com/thrasher-/gocryptotrader/currency/pair"
8 | "github.com/thrasher-/gocryptotrader/exchanges"
9 | "github.com/thrasher-/gocryptotrader/exchanges/orderbook"
10 | "github.com/thrasher-/gocryptotrader/exchanges/ticker"
11 | )
12 |
13 | // Start starts the HUOBI go routine
14 | func (h *HUOBI) Start() {
15 | go h.Run()
16 | }
17 |
18 | // Run implements the HUOBI wrapper
19 | func (h *HUOBI) Run() {
20 | if h.Verbose {
21 | log.Printf("%s Websocket: %s (url: %s).\n", h.GetName(), common.IsEnabled(h.Websocket), HUOBI_SOCKETIO_ADDRESS)
22 | log.Printf("%s polling delay: %ds.\n", h.GetName(), h.RESTPollingDelay)
23 | log.Printf("%s %d currencies enabled: %s.\n", h.GetName(), len(h.EnabledPairs), h.EnabledPairs)
24 | }
25 |
26 | if h.Websocket {
27 | go h.WebsocketClient()
28 | }
29 | }
30 |
31 | // UpdateTicker updates and returns the ticker for a currency pair
32 | func (h *HUOBI) UpdateTicker(p pair.CurrencyPair, assetType string) (ticker.Price, error) {
33 | var tickerPrice ticker.Price
34 | tick, err := h.GetTicker(p.GetFirstCurrency().Lower().String())
35 | if err != nil {
36 | return tickerPrice, err
37 | }
38 | tickerPrice.Pair = p
39 | tickerPrice.Ask = tick.Sell
40 | tickerPrice.Bid = tick.Buy
41 | tickerPrice.Low = tick.Low
42 | tickerPrice.Last = tick.Last
43 | tickerPrice.Volume = tick.Vol
44 | tickerPrice.High = tick.High
45 | ticker.ProcessTicker(h.GetName(), p, tickerPrice, assetType)
46 | return ticker.GetTicker(h.Name, p, assetType)
47 | }
48 |
49 | // GetTickerPrice returns the ticker for a currency pair
50 | func (h *HUOBI) GetTickerPrice(p pair.CurrencyPair, assetType string) (ticker.Price, error) {
51 | tickerNew, err := ticker.GetTicker(h.GetName(), p, assetType)
52 | if err != nil {
53 | return h.UpdateTicker(p, assetType)
54 | }
55 | return tickerNew, nil
56 | }
57 |
58 | // GetOrderbookEx returns orderbook base on the currency pair
59 | func (h *HUOBI) GetOrderbookEx(p pair.CurrencyPair, assetType string) (orderbook.Base, error) {
60 | ob, err := orderbook.GetOrderbook(h.GetName(), p, assetType)
61 | if err == nil {
62 | return h.UpdateOrderbook(p, assetType)
63 | }
64 | return ob, nil
65 | }
66 |
67 | // UpdateOrderbook updates and returns the orderbook for a currency pair
68 | func (h *HUOBI) UpdateOrderbook(p pair.CurrencyPair, assetType string) (orderbook.Base, error) {
69 | var orderBook orderbook.Base
70 | orderbookNew, err := h.GetOrderBook(p.GetFirstCurrency().Lower().String())
71 | if err != nil {
72 | return orderBook, err
73 | }
74 |
75 | for x := range orderbookNew.Bids {
76 | data := orderbookNew.Bids[x]
77 | orderBook.Bids = append(orderBook.Bids, orderbook.Item{Amount: data[1], Price: data[0]})
78 | }
79 |
80 | for x := range orderbookNew.Asks {
81 | data := orderbookNew.Asks[x]
82 | orderBook.Asks = append(orderBook.Asks, orderbook.Item{Amount: data[1], Price: data[0]})
83 | }
84 |
85 | orderbook.ProcessOrderbook(h.GetName(), p, orderBook, assetType)
86 | return orderbook.GetOrderbook(h.Name, p, assetType)
87 | }
88 |
89 | //GetExchangeAccountInfo retrieves balances for all enabled currencies for the
90 | // HUOBI exchange - to-do
91 | func (h *HUOBI) GetExchangeAccountInfo() (exchange.AccountInfo, error) {
92 | var response exchange.AccountInfo
93 | response.ExchangeName = h.GetName()
94 | return response, nil
95 | }
96 |
--------------------------------------------------------------------------------
/exchanges/btcc/btcc_wrapper.go:
--------------------------------------------------------------------------------
1 | package btcc
2 |
3 | import (
4 | "log"
5 |
6 | "github.com/thrasher-/gocryptotrader/common"
7 | "github.com/thrasher-/gocryptotrader/currency/pair"
8 | exchange "github.com/thrasher-/gocryptotrader/exchanges"
9 | "github.com/thrasher-/gocryptotrader/exchanges/orderbook"
10 | "github.com/thrasher-/gocryptotrader/exchanges/ticker"
11 | )
12 |
13 | // Start starts the BTCC go routine
14 | func (b *BTCC) Start() {
15 | go b.Run()
16 | }
17 |
18 | // Run implements the BTCC wrapper
19 | func (b *BTCC) Run() {
20 | if b.Verbose {
21 | log.Printf("%s Websocket: %s.", b.GetName(), common.IsEnabled(b.Websocket))
22 | log.Printf("%s polling delay: %ds.\n", b.GetName(), b.RESTPollingDelay)
23 | log.Printf("%s %d currencies enabled: %s.\n", b.GetName(), len(b.EnabledPairs), b.EnabledPairs)
24 | }
25 |
26 | if b.Websocket {
27 | go b.WebsocketClient()
28 | }
29 | }
30 |
31 | // UpdateTicker updates and returns the ticker for a currency pair
32 | func (b *BTCC) UpdateTicker(p pair.CurrencyPair, assetType string) (ticker.Price, error) {
33 | var tickerPrice ticker.Price
34 | tick, err := b.GetTicker(exchange.FormatExchangeCurrency(b.GetName(), p).String())
35 | if err != nil {
36 | return tickerPrice, err
37 | }
38 | tickerPrice.Pair = p
39 | tickerPrice.Ask = tick.Sell
40 | tickerPrice.Bid = tick.Buy
41 | tickerPrice.Low = tick.Low
42 | tickerPrice.Last = tick.Last
43 | tickerPrice.Volume = tick.Vol
44 | tickerPrice.High = tick.High
45 | ticker.ProcessTicker(b.GetName(), p, tickerPrice, assetType)
46 | return ticker.GetTicker(b.Name, p, assetType)
47 | }
48 |
49 | // GetTickerPrice returns the ticker for a currency pair
50 | func (b *BTCC) GetTickerPrice(p pair.CurrencyPair, assetType string) (ticker.Price, error) {
51 | tickerNew, err := ticker.GetTicker(b.GetName(), p, assetType)
52 | if err != nil {
53 | return b.UpdateTicker(p, assetType)
54 | }
55 | return tickerNew, nil
56 | }
57 |
58 | // GetOrderbookEx returns the orderbook for a currency pair
59 | func (b *BTCC) GetOrderbookEx(p pair.CurrencyPair, assetType string) (orderbook.Base, error) {
60 | ob, err := orderbook.GetOrderbook(b.GetName(), p, assetType)
61 | if err == nil {
62 | return b.UpdateOrderbook(p, assetType)
63 | }
64 | return ob, nil
65 | }
66 |
67 | // UpdateOrderbook updates and returns the orderbook for a currency pair
68 | func (b *BTCC) UpdateOrderbook(p pair.CurrencyPair, assetType string) (orderbook.Base, error) {
69 | var orderBook orderbook.Base
70 | orderbookNew, err := b.GetOrderBook(exchange.FormatExchangeCurrency(b.GetName(), p).String(), 100)
71 | if err != nil {
72 | return orderBook, err
73 | }
74 |
75 | for x := range orderbookNew.Bids {
76 | data := orderbookNew.Bids[x]
77 | orderBook.Bids = append(orderBook.Bids, orderbook.Item{Price: data[0], Amount: data[1]})
78 | }
79 |
80 | for x := range orderbookNew.Asks {
81 | data := orderbookNew.Asks[x]
82 | orderBook.Asks = append(orderBook.Asks, orderbook.Item{Price: data[0], Amount: data[1]})
83 | }
84 |
85 | orderbook.ProcessOrderbook(b.GetName(), p, orderBook, assetType)
86 | return orderbook.GetOrderbook(b.Name, p, assetType)
87 | }
88 |
89 | // GetExchangeAccountInfo : Retrieves balances for all enabled currencies for
90 | // the Kraken exchange - TODO
91 | func (b *BTCC) GetExchangeAccountInfo() (exchange.AccountInfo, error) {
92 | var response exchange.AccountInfo
93 | response.ExchangeName = b.GetName()
94 | return response, nil
95 | }
96 |
--------------------------------------------------------------------------------
/exchanges/wex/wex_test.go:
--------------------------------------------------------------------------------
1 | package wex
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/thrasher-/gocryptotrader/config"
7 | )
8 |
9 | var w WEX
10 |
11 | // Please supply your own keys for better unit testing
12 | const (
13 | apiKey = ""
14 | apiSecret = ""
15 | )
16 |
17 | func TestSetDefaults(t *testing.T) {
18 | w.SetDefaults()
19 | }
20 |
21 | func TestSetup(t *testing.T) {
22 | wexConfig := config.GetConfig()
23 | wexConfig.LoadConfig("../../testdata/configtest.json")
24 | conf, err := wexConfig.GetExchangeConfig("WEX")
25 | if err != nil {
26 | t.Error("Test Failed - WEX init error")
27 | }
28 | conf.APIKey = apiKey
29 | conf.APISecret = apiSecret
30 | conf.AuthenticatedAPISupport = true
31 |
32 | w.Setup(conf)
33 | }
34 |
35 | func TestGetFee(t *testing.T) {
36 | if w.GetFee() != 0.2 {
37 | t.Error("Test Failed - GetFee() error")
38 | }
39 | }
40 |
41 | func TestGetInfo(t *testing.T) {
42 | _, err := w.GetInfo()
43 | if err != nil {
44 | t.Error("Test Failed - GetInfo() error")
45 | }
46 | }
47 |
48 | func TestGetTicker(t *testing.T) {
49 | _, err := w.GetTicker("btc_usd")
50 | if err != nil {
51 | t.Error("Test Failed - GetTicker() error", err)
52 | }
53 | }
54 |
55 | func TestGetDepth(t *testing.T) {
56 | _, err := w.GetDepth("btc_usd")
57 | if err != nil {
58 | t.Error("Test Failed - GetDepth() error", err)
59 | }
60 | }
61 |
62 | func TestGetTrades(t *testing.T) {
63 | _, err := w.GetTrades("btc_usd")
64 | if err != nil {
65 | t.Error("Test Failed - GetTrades() error", err)
66 | }
67 | }
68 |
69 | func TestGetAccountInfo(t *testing.T) {
70 | _, err := w.GetAccountInfo()
71 | if err == nil {
72 | t.Error("Test Failed - GetAccountInfo() error", err)
73 | }
74 | }
75 |
76 | func TestGetActiveOrders(t *testing.T) {
77 | _, err := w.GetActiveOrders("")
78 | if err == nil {
79 | t.Error("Test Failed - GetActiveOrders() error", err)
80 | }
81 | }
82 |
83 | func TestGetOrderInfo(t *testing.T) {
84 | _, err := w.GetOrderInfo(6196974)
85 | if err == nil {
86 | t.Error("Test Failed - GetOrderInfo() error", err)
87 | }
88 | }
89 |
90 | func TestCancelOrder(t *testing.T) {
91 | _, err := w.CancelOrder(1337)
92 | if err == nil {
93 | t.Error("Test Failed - CancelOrder() error", err)
94 | }
95 | }
96 |
97 | func TestTrade(t *testing.T) {
98 | _, err := w.Trade("", "buy", 0, 0)
99 | if err == nil {
100 | t.Error("Test Failed - Trade() error", err)
101 | }
102 | }
103 |
104 | func TestGetTransactionHistory(t *testing.T) {
105 | _, err := w.GetTransactionHistory(0, 0, 0, "", "", "")
106 | if err == nil {
107 | t.Error("Test Failed - GetTransactionHistory() error", err)
108 | }
109 | }
110 |
111 | func TestGetTradeHistory(t *testing.T) {
112 | _, err := w.GetTradeHistory(0, 0, 0, "", "", "", "")
113 | if err == nil {
114 | t.Error("Test Failed - GetTradeHistory() error", err)
115 | }
116 | }
117 |
118 | func TestWithdrawCoins(t *testing.T) {
119 | _, err := w.WithdrawCoins("", 0, "")
120 | if err == nil {
121 | t.Error("Test Failed - WithdrawCoins() error", err)
122 | }
123 | }
124 |
125 | func TestCoinDepositAddress(t *testing.T) {
126 | _, err := w.CoinDepositAddress("btc")
127 | if err == nil {
128 | t.Error("Test Failed - WithdrawCoins() error", err)
129 | }
130 | }
131 |
132 | func TestCreateCoupon(t *testing.T) {
133 | _, err := w.CreateCoupon("bla", 0)
134 | if err == nil {
135 | t.Error("Test Failed - CreateCoupon() error", err)
136 | }
137 | }
138 |
139 | func TestRedeemCoupon(t *testing.T) {
140 | _, err := w.RedeemCoupon("bla")
141 | if err == nil {
142 | t.Error("Test Failed - RedeemCoupon() error", err)
143 | }
144 | }
145 |
--------------------------------------------------------------------------------
/exchanges/localbitcoins/localbitcoins_wrapper.go:
--------------------------------------------------------------------------------
1 | package localbitcoins
2 |
3 | import (
4 | "log"
5 |
6 | "github.com/thrasher-/gocryptotrader/currency/pair"
7 | "github.com/thrasher-/gocryptotrader/exchanges"
8 | "github.com/thrasher-/gocryptotrader/exchanges/orderbook"
9 | "github.com/thrasher-/gocryptotrader/exchanges/ticker"
10 | )
11 |
12 | // Start starts the LocalBitcoins go routine
13 | func (l *LocalBitcoins) Start() {
14 | go l.Run()
15 | }
16 |
17 | // Run implements the LocalBitcoins wrapper
18 | func (l *LocalBitcoins) Run() {
19 | if l.Verbose {
20 | log.Printf("%s polling delay: %ds.\n", l.GetName(), l.RESTPollingDelay)
21 | log.Printf("%s %d currencies enabled: %s.\n", l.GetName(), len(l.EnabledPairs), l.EnabledPairs)
22 | }
23 | }
24 |
25 | // UpdateTicker updates and returns the ticker for a currency pair
26 | func (l *LocalBitcoins) UpdateTicker(p pair.CurrencyPair, assetType string) (ticker.Price, error) {
27 | var tickerPrice ticker.Price
28 | tick, err := l.GetTicker()
29 | if err != nil {
30 | return tickerPrice, err
31 | }
32 |
33 | for _, x := range l.GetEnabledCurrencies() {
34 | currency := x.SecondCurrency.String()
35 | var tp ticker.Price
36 | tp.Pair = x
37 | tp.Last = tick[currency].Avg24h
38 | tp.Volume = tick[currency].VolumeBTC
39 | ticker.ProcessTicker(l.GetName(), x, tp, assetType)
40 | }
41 |
42 | return ticker.GetTicker(l.GetName(), p, assetType)
43 | }
44 |
45 | // GetTickerPrice returns the ticker for a currency pair
46 | func (l *LocalBitcoins) GetTickerPrice(p pair.CurrencyPair, assetType string) (ticker.Price, error) {
47 | tickerNew, err := ticker.GetTicker(l.GetName(), p, assetType)
48 | if err == nil {
49 | return l.UpdateTicker(p, assetType)
50 | }
51 | return tickerNew, nil
52 | }
53 |
54 | // GetOrderbookEx returns orderbook base on the currency pair
55 | func (l *LocalBitcoins) GetOrderbookEx(p pair.CurrencyPair, assetType string) (orderbook.Base, error) {
56 | ob, err := orderbook.GetOrderbook(l.GetName(), p, assetType)
57 | if err == nil {
58 | return l.UpdateOrderbook(p, assetType)
59 | }
60 | return ob, nil
61 | }
62 |
63 | // UpdateOrderbook updates and returns the orderbook for a currency pair
64 | func (l *LocalBitcoins) UpdateOrderbook(p pair.CurrencyPair, assetType string) (orderbook.Base, error) {
65 | var orderBook orderbook.Base
66 | orderbookNew, err := l.GetOrderbook(p.GetSecondCurrency().String())
67 | if err != nil {
68 | return orderBook, err
69 | }
70 |
71 | for x := range orderbookNew.Bids {
72 | data := orderbookNew.Bids[x]
73 | orderBook.Bids = append(orderBook.Bids, orderbook.Item{Amount: data.Amount, Price: data.Price})
74 | }
75 |
76 | for x := range orderbookNew.Asks {
77 | data := orderbookNew.Asks[x]
78 | orderBook.Asks = append(orderBook.Asks, orderbook.Item{Amount: data.Amount, Price: data.Price})
79 | }
80 |
81 | orderbook.ProcessOrderbook(l.GetName(), p, orderBook, assetType)
82 | return orderbook.GetOrderbook(l.Name, p, assetType)
83 | }
84 |
85 | // GetExchangeAccountInfo retrieves balances for all enabled currencies for the
86 | // LocalBitcoins exchange
87 | func (l *LocalBitcoins) GetExchangeAccountInfo() (exchange.AccountInfo, error) {
88 | var response exchange.AccountInfo
89 | response.ExchangeName = l.GetName()
90 | accountBalance, err := l.GetWalletBalance()
91 | if err != nil {
92 | return response, err
93 | }
94 | var exchangeCurrency exchange.AccountCurrencyInfo
95 | exchangeCurrency.CurrencyName = "BTC"
96 | exchangeCurrency.TotalValue = accountBalance.Total.Balance
97 |
98 | response.Currencies = append(response.Currencies, exchangeCurrency)
99 | return response, nil
100 | }
101 |
--------------------------------------------------------------------------------
/exchanges/lakebtc/lakebtc_types.go:
--------------------------------------------------------------------------------
1 | package lakebtc
2 |
3 | // Ticker holds ticker information
4 | type Ticker struct {
5 | Last float64
6 | Bid float64
7 | Ask float64
8 | High float64
9 | Low float64
10 | Volume float64
11 | }
12 |
13 | // OrderbookStructure stores price and amount for order books
14 | type OrderbookStructure struct {
15 | Price float64
16 | Amount float64
17 | }
18 |
19 | // Orderbook contains arrays of orderbook information
20 | type Orderbook struct {
21 | Bids []OrderbookStructure `json:"bids"`
22 | Asks []OrderbookStructure `json:"asks"`
23 | }
24 |
25 | // TickerResponse stores temp response
26 | // Silly hack due to API returning null instead of strings
27 | type TickerResponse struct {
28 | Last interface{}
29 | Bid interface{}
30 | Ask interface{}
31 | High interface{}
32 | Low interface{}
33 | Volume interface{}
34 | }
35 |
36 | // TradeHistory holds trade history data
37 | type TradeHistory struct {
38 | Date int64 `json:"data"`
39 | Price float64 `json:"price,string"`
40 | Amount float64 `json:"amount,string"`
41 | TID int64 `json:"tid"`
42 | }
43 |
44 | // AccountInfo contains account information
45 | type AccountInfo struct {
46 | Balance map[string]string `json:"balance"`
47 | Locked map[string]string `json:"locked"`
48 | Profile struct {
49 | Email string `json:"email"`
50 | UID string `json:"uid"`
51 | BTCDepositAddress string `json:"btc_deposit_addres"`
52 | } `json:"profile"`
53 | }
54 |
55 | // Trade holds trade information
56 | type Trade struct {
57 | ID int64 `json:"id"`
58 | Result string `json:"result"`
59 | }
60 |
61 | // OpenOrders stores full information on your open orders
62 | type OpenOrders struct {
63 | ID int64 `json:"id"`
64 | Amount float64 `json:"amount,string"`
65 | Price float64 `json:"price,string"`
66 | Symbol string `json:"symbol"`
67 | Type string `json:"type"`
68 | At int64 `json:"at"`
69 | }
70 |
71 | // Orders holds current order information
72 | type Orders struct {
73 | ID int64 `json:"id"`
74 | OriginalAmount float64 `json:"original_amount,string"`
75 | Amount float64 `json:"amount,string"`
76 | Price float64 `json:"price,string"`
77 | Symbol string `json:"symbol"`
78 | Type string `json:"type"`
79 | State string `json:"state"`
80 | At int64 `json:"at"`
81 | }
82 |
83 | // AuthenticatedTradeHistory is a store of personalised auth trade history
84 | type AuthenticatedTradeHistory struct {
85 | Type string `json:"type"`
86 | Symbol string `json:"symbol"`
87 | Amount float64 `json:"amount,string"`
88 | Total float64 `json:"total,string"`
89 | At int64 `json:"at"`
90 | }
91 |
92 | // ExternalAccounts holds external account information
93 | type ExternalAccounts struct {
94 | ID int64 `json:"id,string"`
95 | Type string `json:"type"`
96 | Address string `json:"address"`
97 | Alias interface{} `json:"alias"`
98 | Currencies string `json:"currencies"`
99 | State string `json:"state"`
100 | UpdatedAt int64 `json:"updated_at,string"`
101 | }
102 |
103 | // Withdraw holds withdrawal information
104 | type Withdraw struct {
105 | ID int64 `json:"id,string"`
106 | Amount float64 `json:"amount,string"`
107 | Currency string `json:"currency"`
108 | Fee float64 `json:"fee,string"`
109 | State string `json:"state"`
110 | Source string `json:"source"`
111 | ExternalAccountID int64 `json:"external_account_id,string"`
112 | At int64 `json:"at"`
113 | }
114 |
--------------------------------------------------------------------------------
/exchanges/itbit/itbit_wrapper.go:
--------------------------------------------------------------------------------
1 | package itbit
2 |
3 | import (
4 | "log"
5 | "strconv"
6 |
7 | "github.com/thrasher-/gocryptotrader/currency/pair"
8 | "github.com/thrasher-/gocryptotrader/exchanges"
9 | "github.com/thrasher-/gocryptotrader/exchanges/orderbook"
10 | "github.com/thrasher-/gocryptotrader/exchanges/ticker"
11 | )
12 |
13 | // Start starts the ItBit go routine
14 | func (i *ItBit) Start() {
15 | go i.Run()
16 | }
17 |
18 | // Run implements the ItBit wrapper
19 | func (i *ItBit) Run() {
20 | if i.Verbose {
21 | log.Printf("%s polling delay: %ds.\n", i.GetName(), i.RESTPollingDelay)
22 | log.Printf("%s %d currencies enabled: %s.\n", i.GetName(), len(i.EnabledPairs), i.EnabledPairs)
23 | }
24 | }
25 |
26 | // UpdateTicker updates and returns the ticker for a currency pair
27 | func (i *ItBit) UpdateTicker(p pair.CurrencyPair, assetType string) (ticker.Price, error) {
28 | var tickerPrice ticker.Price
29 | tick, err := i.GetTicker(exchange.FormatExchangeCurrency(i.Name,
30 | p).String())
31 | if err != nil {
32 | return tickerPrice, err
33 | }
34 |
35 | tickerPrice.Pair = p
36 | tickerPrice.Ask = tick.Ask
37 | tickerPrice.Bid = tick.Bid
38 | tickerPrice.Last = tick.LastPrice
39 | tickerPrice.High = tick.High24h
40 | tickerPrice.Low = tick.Low24h
41 | tickerPrice.Volume = tick.Volume24h
42 | ticker.ProcessTicker(i.GetName(), p, tickerPrice, assetType)
43 | return ticker.GetTicker(i.Name, p, assetType)
44 | }
45 |
46 | // GetTickerPrice returns the ticker for a currency pair
47 | func (i *ItBit) GetTickerPrice(p pair.CurrencyPair, assetType string) (ticker.Price, error) {
48 | tickerNew, err := ticker.GetTicker(i.GetName(), p, assetType)
49 | if err != nil {
50 | return i.UpdateTicker(p, assetType)
51 | }
52 | return tickerNew, nil
53 | }
54 |
55 | // GetOrderbookEx returns orderbook base on the currency pair
56 | func (i *ItBit) GetOrderbookEx(p pair.CurrencyPair, assetType string) (orderbook.Base, error) {
57 | ob, err := orderbook.GetOrderbook(i.GetName(), p, assetType)
58 | if err == nil {
59 | return i.UpdateOrderbook(p, assetType)
60 | }
61 | return ob, nil
62 | }
63 |
64 | // UpdateOrderbook updates and returns the orderbook for a currency pair
65 | func (i *ItBit) UpdateOrderbook(p pair.CurrencyPair, assetType string) (orderbook.Base, error) {
66 | var orderBook orderbook.Base
67 | orderbookNew, err := i.GetOrderbook(exchange.FormatExchangeCurrency(i.Name,
68 | p).String())
69 | if err != nil {
70 | return orderBook, err
71 | }
72 |
73 | for x := range orderbookNew.Bids {
74 | data := orderbookNew.Bids[x]
75 | price, err := strconv.ParseFloat(data[0], 64)
76 | if err != nil {
77 | log.Println(err)
78 | }
79 | amount, err := strconv.ParseFloat(data[1], 64)
80 | if err != nil {
81 | log.Println(err)
82 | }
83 | orderBook.Bids = append(orderBook.Bids, orderbook.Item{Amount: amount, Price: price})
84 | }
85 |
86 | for x := range orderbookNew.Asks {
87 | data := orderbookNew.Asks[x]
88 | price, err := strconv.ParseFloat(data[0], 64)
89 | if err != nil {
90 | log.Println(err)
91 | }
92 | amount, err := strconv.ParseFloat(data[1], 64)
93 | if err != nil {
94 | log.Println(err)
95 | }
96 | orderBook.Asks = append(orderBook.Asks, orderbook.Item{Amount: amount, Price: price})
97 | }
98 |
99 | orderbook.ProcessOrderbook(i.GetName(), p, orderBook, assetType)
100 | return orderbook.GetOrderbook(i.Name, p, assetType)
101 | }
102 |
103 | // GetExchangeAccountInfo retrieves balances for all enabled currencies for the
104 | //ItBit exchange - to-do
105 | func (i *ItBit) GetExchangeAccountInfo() (exchange.AccountInfo, error) {
106 | var response exchange.AccountInfo
107 | response.ExchangeName = i.GetName()
108 | return response, nil
109 | }
110 |
--------------------------------------------------------------------------------
/exchanges/anx/anx_wrapper.go:
--------------------------------------------------------------------------------
1 | package anx
2 |
3 | import (
4 | "log"
5 | "strconv"
6 |
7 | "github.com/thrasher-/gocryptotrader/currency/pair"
8 | "github.com/thrasher-/gocryptotrader/exchanges"
9 | "github.com/thrasher-/gocryptotrader/exchanges/orderbook"
10 | "github.com/thrasher-/gocryptotrader/exchanges/ticker"
11 | )
12 |
13 | // Start starts the ANX go routine
14 | func (a *ANX) Start() {
15 | go a.Run()
16 | }
17 |
18 | // Run implements the ANX wrapper
19 | func (a *ANX) Run() {
20 | if a.Verbose {
21 | log.Printf("%s polling delay: %ds.\n", a.GetName(), a.RESTPollingDelay)
22 | log.Printf("%s %d currencies enabled: %s.\n", a.GetName(), len(a.EnabledPairs), a.EnabledPairs)
23 | }
24 | }
25 |
26 | // UpdateTicker updates and returns the ticker for a currency pair
27 | func (a *ANX) UpdateTicker(p pair.CurrencyPair, assetType string) (ticker.Price, error) {
28 | var tickerPrice ticker.Price
29 | tick, err := a.GetTicker(exchange.FormatExchangeCurrency(a.GetName(), p).String())
30 | if err != nil {
31 | return tickerPrice, err
32 | }
33 |
34 | tickerPrice.Pair = p
35 |
36 | if tick.Data.Sell.Value != "" {
37 | tickerPrice.Ask, err = strconv.ParseFloat(tick.Data.Sell.Value, 64)
38 | if err != nil {
39 | return tickerPrice, err
40 | }
41 | } else {
42 | tickerPrice.Ask = 0
43 | }
44 |
45 | if tick.Data.Buy.Value != "" {
46 | tickerPrice.Bid, err = strconv.ParseFloat(tick.Data.Buy.Value, 64)
47 | if err != nil {
48 | return tickerPrice, err
49 | }
50 | } else {
51 | tickerPrice.Bid = 0
52 | }
53 |
54 | if tick.Data.Low.Value != "" {
55 | tickerPrice.Low, err = strconv.ParseFloat(tick.Data.Low.Value, 64)
56 | if err != nil {
57 | return tickerPrice, err
58 | }
59 | } else {
60 | tickerPrice.Low = 0
61 | }
62 |
63 | if tick.Data.Last.Value != "" {
64 | tickerPrice.Last, err = strconv.ParseFloat(tick.Data.Last.Value, 64)
65 | if err != nil {
66 | return tickerPrice, err
67 | }
68 | } else {
69 | tickerPrice.Last = 0
70 | }
71 |
72 | if tick.Data.Vol.Value != "" {
73 | tickerPrice.Volume, err = strconv.ParseFloat(tick.Data.Vol.Value, 64)
74 | if err != nil {
75 | return tickerPrice, err
76 | }
77 | } else {
78 | tickerPrice.Volume = 0
79 | }
80 |
81 | if tick.Data.High.Value != "" {
82 | tickerPrice.High, err = strconv.ParseFloat(tick.Data.High.Value, 64)
83 | if err != nil {
84 | return tickerPrice, err
85 | }
86 | } else {
87 | tickerPrice.High = 0
88 | }
89 | ticker.ProcessTicker(a.GetName(), p, tickerPrice, assetType)
90 | return ticker.GetTicker(a.Name, p, assetType)
91 | }
92 |
93 | // GetTickerPrice returns the ticker for a currency pair
94 | func (a *ANX) GetTickerPrice(p pair.CurrencyPair, assetType string) (ticker.Price, error) {
95 | tickerNew, err := ticker.GetTicker(a.GetName(), p, assetType)
96 | if err != nil {
97 | return a.UpdateTicker(p, assetType)
98 | }
99 | return tickerNew, nil
100 | }
101 |
102 | // GetOrderbookEx returns the orderbook for a currency pair
103 | func (a *ANX) GetOrderbookEx(p pair.CurrencyPair, assetType string) (orderbook.Base, error) {
104 | ob, err := orderbook.GetOrderbook(a.GetName(), p, assetType)
105 | if err == nil {
106 | return a.UpdateOrderbook(p, assetType)
107 | }
108 | return ob, nil
109 | }
110 |
111 | // UpdateOrderbook updates and returns the orderbook for a currency pair
112 | func (a *ANX) UpdateOrderbook(p pair.CurrencyPair, assetType string) (orderbook.Base, error) {
113 | var orderBook orderbook.Base
114 | return orderBook, nil
115 | }
116 |
117 | //GetExchangeAccountInfo : Retrieves balances for all enabled currencies for the ANX exchange
118 | func (a *ANX) GetExchangeAccountInfo() (exchange.AccountInfo, error) {
119 | var response exchange.AccountInfo
120 | response.ExchangeName = a.GetName()
121 | return response, nil
122 | }
123 |
--------------------------------------------------------------------------------
/exchanges/itbit/itbit_test.go:
--------------------------------------------------------------------------------
1 | package itbit
2 |
3 | import (
4 | "net/url"
5 | "testing"
6 |
7 | "github.com/thrasher-/gocryptotrader/config"
8 | )
9 |
10 | var i ItBit
11 |
12 | // Please provide your own keys to do proper testing
13 | const (
14 | apiKey = ""
15 | apiSecret = ""
16 | clientID = ""
17 | )
18 |
19 | func TestSetDefaults(t *testing.T) {
20 | i.SetDefaults()
21 | }
22 |
23 | func TestSetup(t *testing.T) {
24 | cfg := config.GetConfig()
25 | cfg.LoadConfig("../../testdata/configtest.json")
26 | itbitConfig, err := cfg.GetExchangeConfig("ITBIT")
27 | if err != nil {
28 | t.Error("Test Failed - Gemini Setup() init error")
29 | }
30 |
31 | itbitConfig.AuthenticatedAPISupport = true
32 | itbitConfig.APIKey = apiKey
33 | itbitConfig.APISecret = apiSecret
34 | itbitConfig.ClientID = clientID
35 |
36 | i.Setup(itbitConfig)
37 | }
38 |
39 | func TestGetFee(t *testing.T) {
40 | t.Parallel()
41 | if i.GetFee(true) != -0.1 || i.GetFee(false) != 0.5 {
42 | t.Error("Test Failed - GetFee() error")
43 | }
44 | }
45 |
46 | func TestGetTicker(t *testing.T) {
47 | t.Parallel()
48 | _, err := i.GetTicker("XBTUSD")
49 | if err != nil {
50 | t.Error("Test Failed - GetTicker() error", err)
51 | }
52 | }
53 |
54 | func TestGetOrderbook(t *testing.T) {
55 | t.Parallel()
56 | _, err := i.GetOrderbook("XBTSGD")
57 | if err != nil {
58 | t.Error("Test Failed - GetOrderbook() error", err)
59 | }
60 | }
61 |
62 | func TestGetTradeHistory(t *testing.T) {
63 | t.Parallel()
64 | _, err := i.GetTradeHistory("XBTUSD", "0")
65 | if err != nil {
66 | t.Error("Test Failed - GetTradeHistory() error", err)
67 | }
68 | }
69 |
70 | func TestGetWallets(t *testing.T) {
71 | _, err := i.GetWallets(url.Values{})
72 | if err == nil {
73 | t.Error("Test Failed - GetWallets() error", err)
74 | }
75 | }
76 |
77 | func TestCreateWallet(t *testing.T) {
78 | _, err := i.CreateWallet("test")
79 | if err == nil {
80 | t.Error("Test Failed - CreateWallet() error", err)
81 | }
82 | }
83 |
84 | func TestGetWallet(t *testing.T) {
85 | _, err := i.GetWallet("1337")
86 | if err == nil {
87 | t.Error("Test Failed - GetWallet() error", err)
88 | }
89 | }
90 |
91 | func TestGetWalletBalance(t *testing.T) {
92 | _, err := i.GetWalletBalance("1337", "XRT")
93 | if err == nil {
94 | t.Error("Test Failed - GetWalletBalance() error", err)
95 | }
96 | }
97 |
98 | func TestGetWalletTrades(t *testing.T) {
99 | _, err := i.GetWalletTrades("1337", url.Values{})
100 | if err == nil {
101 | t.Error("Test Failed - GetWalletTrades() error", err)
102 | }
103 | }
104 |
105 | func TestGetFundingHistory(t *testing.T) {
106 | _, err := i.GetFundingHistory("1337", url.Values{})
107 | if err == nil {
108 | t.Error("Test Failed - GetFundingHistory() error", err)
109 | }
110 | }
111 |
112 | func TestPlaceOrder(t *testing.T) {
113 | _, err := i.PlaceOrder("1337", "buy", "limit", "USD", 1, 0.2, "banjo", "sauce")
114 | if err == nil {
115 | t.Error("Test Failed - PlaceOrder() error", err)
116 | }
117 | }
118 |
119 | func TestGetOrder(t *testing.T) {
120 | _, err := i.GetOrder("1337", url.Values{})
121 | if err == nil {
122 | t.Error("Test Failed - GetOrder() error", err)
123 | }
124 | }
125 |
126 | func TestCancelOrder(t *testing.T) {
127 | t.Skip()
128 | err := i.CancelOrder("1337", "1337order")
129 | if err == nil {
130 | t.Error("Test Failed - CancelOrder() error", err)
131 | }
132 | }
133 |
134 | func TestGetDepositAddress(t *testing.T) {
135 | _, err := i.GetDepositAddress("1337", "AUD")
136 | if err == nil {
137 | t.Error("Test Failed - GetDepositAddress() error", err)
138 | }
139 | }
140 |
141 | func TestWalletTransfer(t *testing.T) {
142 | _, err := i.WalletTransfer("1337", "mywallet", "anotherwallet", 200, "USD")
143 | if err == nil {
144 | t.Error("Test Failed - WalletTransfer() error", err)
145 | }
146 | }
147 |
--------------------------------------------------------------------------------
/config/config_encryption.go:
--------------------------------------------------------------------------------
1 | package config
2 |
3 | import (
4 | "bytes"
5 | "crypto/aes"
6 | "crypto/cipher"
7 | "crypto/rand"
8 | "errors"
9 | "fmt"
10 | "io"
11 | "log"
12 | "reflect"
13 |
14 | "github.com/thrasher-/gocryptotrader/common"
15 | )
16 |
17 | const (
18 | // EncryptConfirmString has a the general confirmation string to allow us to
19 | // see if the file is correctly encrypted
20 | EncryptConfirmString = "THORS-HAMMER"
21 | errAESBlockSize = "The config file data is too small for the AES required block size"
22 | errNotAPointer = "Error: parameter interface is not a pointer"
23 | )
24 |
25 | // PromptForConfigEncryption asks for encryption key
26 | func (c *Config) PromptForConfigEncryption() bool {
27 | log.Println("Would you like to encrypt your config file (y/n)?")
28 |
29 | input := ""
30 | _, err := fmt.Scanln(&input)
31 | if err != nil {
32 | return false
33 | }
34 |
35 | if !common.YesOrNo(input) {
36 | c.EncryptConfig = configFileEncryptionDisabled
37 | c.SaveConfig("")
38 | return false
39 | }
40 | return true
41 | }
42 |
43 | // PromptForConfigKey asks for configuration key
44 | func PromptForConfigKey() ([]byte, error) {
45 | var cryptoKey []byte
46 |
47 | for len(cryptoKey) != 32 {
48 | log.Println("Enter password (32 characters):")
49 |
50 | _, err := fmt.Scanln(&cryptoKey)
51 | if err != nil {
52 | return nil, err
53 | }
54 |
55 | if len(cryptoKey) > 32 || len(cryptoKey) < 32 {
56 | log.Println("Please re-enter password (32 characters):")
57 | }
58 | }
59 | nonce := make([]byte, 12)
60 | if _, err := io.ReadFull(rand.Reader, nonce); err != nil {
61 | return nil, err
62 | }
63 |
64 | return cryptoKey, nil
65 | }
66 |
67 | // EncryptConfigFile encrypts configuration data that is parsed in with a key
68 | // and returns it as a byte array with an error
69 | func EncryptConfigFile(configData, key []byte) ([]byte, error) {
70 | block, err := aes.NewCipher(key)
71 | if err != nil {
72 | return nil, err
73 | }
74 |
75 | ciphertext := make([]byte, aes.BlockSize+len(configData))
76 | iv := ciphertext[:aes.BlockSize]
77 | if _, err := io.ReadFull(rand.Reader, iv); err != nil {
78 | return nil, err
79 | }
80 |
81 | stream := cipher.NewCFBEncrypter(block, iv)
82 | stream.XORKeyStream(ciphertext[aes.BlockSize:], configData)
83 |
84 | appendedFile := []byte(EncryptConfirmString)
85 | appendedFile = append(appendedFile, ciphertext...)
86 | return appendedFile, nil
87 | }
88 |
89 | // DecryptConfigFile decrypts configuration data with the supplied key and
90 | // returns the un-encrypted file as a byte array with an error
91 | func DecryptConfigFile(configData, key []byte) ([]byte, error) {
92 | configData = RemoveECS(configData)
93 | blockDecrypt, err := aes.NewCipher(key)
94 | if err != nil {
95 | return nil, err
96 | }
97 |
98 | if len(configData) < aes.BlockSize {
99 | return nil, errors.New(errAESBlockSize)
100 | }
101 |
102 | iv := configData[:aes.BlockSize]
103 | configData = configData[aes.BlockSize:]
104 |
105 | stream := cipher.NewCFBDecrypter(blockDecrypt, iv)
106 | stream.XORKeyStream(configData, configData)
107 | result := configData
108 | return result, nil
109 | }
110 |
111 | // ConfirmConfigJSON confirms JSON in file
112 | func ConfirmConfigJSON(file []byte, result interface{}) error {
113 | if !common.StringContains(reflect.TypeOf(result).String(), "*") {
114 | return errors.New(errNotAPointer)
115 | }
116 | return common.JSONDecode(file, &result)
117 | }
118 |
119 | // ConfirmECS confirms that the encryption confirmation string is found
120 | func ConfirmECS(file []byte) bool {
121 | subslice := []byte(EncryptConfirmString)
122 | return bytes.Contains(file, subslice)
123 | }
124 |
125 | // RemoveECS removes encryption confirmation string
126 | func RemoveECS(file []byte) []byte {
127 | return bytes.Trim(file, EncryptConfirmString)
128 | }
129 |
--------------------------------------------------------------------------------
/exchanges/btcmarkets/btcmarkets_test.go:
--------------------------------------------------------------------------------
1 | package btcmarkets
2 |
3 | import (
4 | "net/url"
5 | "testing"
6 | "time"
7 |
8 | "github.com/thrasher-/gocryptotrader/config"
9 | )
10 |
11 | var bm BTCMarkets
12 |
13 | // Please supply your own keys here to do better tests
14 | const (
15 | apiKey = ""
16 | apiSecret = ""
17 | )
18 |
19 | func TestSetDefaults(t *testing.T) {
20 | bm.SetDefaults()
21 | }
22 |
23 | func TestSetup(t *testing.T) {
24 | t.Parallel()
25 | b := BTCMarkets{}
26 | b.Name = "BTC Markets"
27 | cfg := config.GetConfig()
28 | cfg.LoadConfig("../../testdata/configtest.json")
29 | bConfig, err := cfg.GetExchangeConfig("BTC Markets")
30 | if err != nil {
31 | t.Error("Test Failed - BTC Markets Setup() init error")
32 | }
33 |
34 | b.SetDefaults()
35 | b.Setup(bConfig)
36 |
37 | if !b.IsEnabled() || b.AuthenticatedAPISupport || b.RESTPollingDelay != time.Duration(10) ||
38 | b.Verbose || b.Websocket || len(b.BaseCurrencies) < 1 ||
39 | len(b.AvailablePairs) < 1 || len(b.EnabledPairs) < 1 {
40 | t.Error("Test Failed - BTC Markets Setup values not set correctly")
41 | }
42 |
43 | bConfig.Enabled = false
44 | b.Setup(bConfig)
45 |
46 | if b.IsEnabled() {
47 | t.Error("Test failed - BTC Markets TestSetup incorrect value")
48 | }
49 | }
50 |
51 | func TestGetFee(t *testing.T) {
52 | t.Parallel()
53 | if fee := bm.GetFee(); fee == 0 {
54 | t.Error("Test failed - GetFee() error")
55 | }
56 | }
57 |
58 | func TestGetTicker(t *testing.T) {
59 | t.Parallel()
60 | _, err := bm.GetTicker("BTC")
61 | if err != nil {
62 | t.Error("Test failed - GetTicker() error", err)
63 | }
64 | }
65 |
66 | func TestGetOrderbook(t *testing.T) {
67 | t.Parallel()
68 | _, err := bm.GetOrderbook("BTC")
69 | if err != nil {
70 | t.Error("Test failed - GetOrderbook() error", err)
71 | }
72 | }
73 |
74 | func TestGetTrades(t *testing.T) {
75 | t.Parallel()
76 | _, err := bm.GetTrades("BTC", nil)
77 | if err != nil {
78 | t.Error("Test failed - GetTrades() error", err)
79 | }
80 |
81 | val := url.Values{}
82 | val.Set("since", "0")
83 | _, err = bm.GetTrades("BTC", val)
84 | if err != nil {
85 | t.Error("Test failed - GetTrades() error", err)
86 | }
87 | }
88 |
89 | func TestNewOrder(t *testing.T) {
90 | t.Parallel()
91 | _, err := bm.NewOrder("AUD", "BTC", 0, 0, "Bid", "limit", "testTest")
92 | if err == nil {
93 | t.Error("Test failed - NewOrder() error", err)
94 | }
95 | }
96 |
97 | func TestCancelOrder(t *testing.T) {
98 | t.Parallel()
99 | _, err := bm.CancelOrder([]int64{1337})
100 | if err == nil {
101 | t.Error("Test failed - CancelOrder() error", err)
102 | }
103 | }
104 |
105 | func TestGetOrders(t *testing.T) {
106 | t.Parallel()
107 | _, err := bm.GetOrders("AUD", "BTC", 10, 0, false)
108 | if err == nil {
109 | t.Error("Test failed - GetOrders() error", err)
110 | }
111 | _, err = bm.GetOrders("AUD", "BTC", 10, 0, true)
112 | if err == nil {
113 | t.Error("Test failed - GetOrders() error", err)
114 | }
115 | }
116 |
117 | func TestGetOrderDetail(t *testing.T) {
118 | t.Parallel()
119 | _, err := bm.GetOrderDetail([]int64{1337})
120 | if err == nil {
121 | t.Error("Test failed - GetOrderDetail() error", err)
122 | }
123 | }
124 |
125 | func TestGetAccountBalance(t *testing.T) {
126 | t.Parallel()
127 | _, err := bm.GetAccountBalance()
128 | if err == nil {
129 | t.Error("Test failed - GetAccountBalance() error", err)
130 | }
131 | }
132 |
133 | func TestWithdrawCrypto(t *testing.T) {
134 | t.Parallel()
135 | _, err := bm.WithdrawCrypto(0, "BTC", "LOLOLOL")
136 | if err == nil {
137 | t.Error("Test failed - WithdrawCrypto() error", err)
138 | }
139 | }
140 |
141 | func TestWithdrawAUD(t *testing.T) {
142 | t.Parallel()
143 | _, err := bm.WithdrawAUD("BLA", "1337", "blawest", "1336", "BTC", 10000000)
144 | if err == nil {
145 | t.Error("Test failed - WithdrawAUD() error", err)
146 | }
147 | }
148 |
--------------------------------------------------------------------------------
/exchanges/liqui/liqui_types.go:
--------------------------------------------------------------------------------
1 | package liqui
2 |
3 | // Info holds the current pair information as well as server time
4 | type Info struct {
5 | ServerTime int64 `json:"server_time"`
6 | Pairs map[string]PairData `json:"pairs"`
7 | }
8 |
9 | // PairData is a sub-type for Info
10 | type PairData struct {
11 | DecimalPlaces int `json:"decimal_places"`
12 | MinPrice float64 `json:"min_price"`
13 | MaxPrice float64 `json:"max_price"`
14 | MinAmount float64 `json:"min_amount"`
15 | Hidden int `json:"hidden"`
16 | Fee float64 `json:"fee"`
17 | }
18 |
19 | // Ticker contains ticker information
20 | type Ticker struct {
21 | High float64
22 | Low float64
23 | Avg float64
24 | Vol float64
25 | Vol_cur float64
26 | Last float64
27 | Buy float64
28 | Sell float64
29 | Updated int64
30 | }
31 |
32 | // Orderbook references both ask and bid sides
33 | type Orderbook struct {
34 | Asks [][]float64 `json:"asks"`
35 | Bids [][]float64 `json:"bids"`
36 | }
37 |
38 | // Trades contains trade information
39 | type Trades struct {
40 | Type string `json:"type"`
41 | Price float64 `json:"bid"`
42 | Amount float64 `json:"amount"`
43 | TID int64 `json:"tid"`
44 | Timestamp int64 `json:"timestamp"`
45 | }
46 |
47 | // AccountInfo contains full account details information
48 | type AccountInfo struct {
49 | Funds map[string]float64 `json:"funds"`
50 | Rights struct {
51 | Info bool `json:"info"`
52 | Trade bool `json:"trade"`
53 | Withdraw bool `json:"withdraw"`
54 | } `json:"rights"`
55 | ServerTime float64 `json:"server_time"`
56 | TransactionCount int `json:"transaction_count"`
57 | OpenOrders int `json:"open_orders"`
58 | }
59 |
60 | // ActiveOrders holds active order information
61 | type ActiveOrders struct {
62 | Pair string `json:"pair"`
63 | Type string `json:"sell"`
64 | Amount float64 `json:"amount"`
65 | Rate float64 `json:"rate"`
66 | TimestampCreated float64 `json:"time_created"`
67 | Status int `json:"status"`
68 | }
69 |
70 | // OrderInfo holds specific order information
71 | type OrderInfo struct {
72 | Pair string `json:"pair"`
73 | Type string `json:"sell"`
74 | StartAmount float64 `json:"start_amount"`
75 | Amount float64 `json:"amount"`
76 | Rate float64 `json:"rate"`
77 | TimestampCreated float64 `json:"time_created"`
78 | Status int `json:"status"`
79 | }
80 |
81 | // CancelOrder holds cancelled order information
82 | type CancelOrder struct {
83 | OrderID float64 `json:"order_id"`
84 | Funds map[string]float64 `json:"funds"`
85 | }
86 |
87 | // Trade holds trading information
88 | type Trade struct {
89 | Received float64 `json:"received"`
90 | Remains float64 `json:"remains"`
91 | OrderID float64 `json:"order_id"`
92 | Funds map[string]float64 `json:"funds"`
93 | }
94 |
95 | // TradeHistory contains trade history data
96 | type TradeHistory struct {
97 | Pair string `json:"pair"`
98 | Type string `json:"type"`
99 | Amount float64 `json:"amount"`
100 | Rate float64 `json:"rate"`
101 | OrderID float64 `json:"order_id"`
102 | MyOrder int `json:"is_your_order"`
103 | Timestamp float64 `json:"timestamp"`
104 | }
105 |
106 | // Response is a generalized return type
107 | type Response struct {
108 | Return interface{} `json:"return"`
109 | Success int `json:"success"`
110 | Error string `json:"error"`
111 | }
112 |
113 | // WithdrawCoins shows the amount of coins withdrawn from liqui not yet available
114 | type WithdrawCoins struct {
115 | TID int64 `json:"tId"`
116 | AmountSent float64 `json:"amountSent"`
117 | Funds map[string]float64 `json:"funds"`
118 | }
119 |
--------------------------------------------------------------------------------