Several changes
- List generation delay on currency choice activity reduced - Sort currencies by market order in currencies selection activity - Rewritten suggestion list - Add default icon when currencies' icons are missing - Optimize details storage - Enable Binance key input - Replacing Binance library by compiled jar from API's github - New main gradient - Fix crash when balance requests complete before details request
This commit is contained in:
parent
1363c04202
commit
375afee570
@ -34,7 +34,15 @@ dependencies {
|
||||
implementation 'com.android.support:recyclerview-v7:26.1.0'
|
||||
implementation 'com.daimajia.swipelayout:library:1.2.0@aar'
|
||||
implementation 'com.github.armcha:SpaceNavigationView:1.6.0'
|
||||
implementation 'com.fasterxml.jackson.core:jackson-databind:2.8.5'
|
||||
implementation 'com.fasterxml.jackson.core:jackson-core:2.8.5'
|
||||
implementation 'com.fasterxml.jackson.core:jackson-annotations:2.8.5'
|
||||
implementation 'com.squareup.retrofit2:retrofit:2.2.0'
|
||||
implementation 'com.squareup.retrofit2:converter-jackson:2.2.0'
|
||||
implementation 'com.squareup.okhttp3:logging-interceptor:3.6.0'
|
||||
implementation 'org.apache.commons:commons-lang3:3.6'
|
||||
testImplementation 'junit:junit:4.12'
|
||||
androidTestImplementation 'com.android.support.test:runner:1.0.1'
|
||||
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
|
||||
implementation files('C:/Users/Guitoune/Documents/GitHub/Coinfolio/libs/binance-api.jar')
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ import android.support.test.runner.AndroidJUnit4;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
* Instrumented test, which will execute on an Android device.
|
||||
|
@ -2,12 +2,10 @@ package com.nauk.coinfolio.Activities;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.design.widget.BottomNavigationView;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.util.Log;
|
||||
import android.view.Gravity;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MenuItem;
|
||||
|
@ -1,15 +1,20 @@
|
||||
package com.nauk.coinfolio.Activities;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.text.TextUtils;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.Menu;
|
||||
import android.view.View;
|
||||
import android.view.Window;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.AutoCompleteTextView;
|
||||
import android.widget.EditText;
|
||||
import android.widget.ListView;
|
||||
import android.widget.SearchView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.nauk.coinfolio.DataManagers.CurrencyData.Currency;
|
||||
import com.nauk.coinfolio.LayoutManagers.CurrencyAdapter;
|
||||
@ -17,10 +22,13 @@ import com.nauk.coinfolio.R;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class CurrencySelectionActivity extends AppCompatActivity {
|
||||
public class CurrencySelectionActivity extends AppCompatActivity implements SearchView.OnQueryTextListener{
|
||||
|
||||
String[] currencySymbols;
|
||||
String[] currencyNames;
|
||||
private String[] currencySymbols;
|
||||
private String[] currencyNames;
|
||||
private CurrencyAdapter adapter;
|
||||
private ListView listView;
|
||||
private android.widget.Filter filter;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
@ -37,25 +45,21 @@ public class CurrencySelectionActivity extends AppCompatActivity {
|
||||
currencyNames = intent.getStringArrayExtra("currencyListNames");
|
||||
|
||||
setTitle("Select a coin");
|
||||
|
||||
setupAdapter();
|
||||
|
||||
setupList();
|
||||
|
||||
SearchView searchView = findViewById(R.id.search_bar);
|
||||
|
||||
searchView.setIconifiedByDefault(false);
|
||||
searchView.setOnQueryTextListener(this);
|
||||
searchView.setSubmitButtonEnabled(false);
|
||||
searchView.onActionViewExpanded();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu)
|
||||
private void setupAdapter()
|
||||
{
|
||||
final AutoCompleteTextView searchAutoComplete = findViewById(R.id.search_bar);
|
||||
|
||||
searchAutoComplete.setOnItemClickListener(new AdapterView.OnItemClickListener() {
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
|
||||
Currency selectedCurrency = (Currency) adapterView.getItemAtPosition(i);
|
||||
Intent intent = new Intent(CurrencySelectionActivity.this, RecordTransactionActivity.class);
|
||||
intent.putExtra("coin", selectedCurrency.getName());
|
||||
intent.putExtra("symbol", selectedCurrency.getSymbol());
|
||||
startActivity(intent);
|
||||
finish();
|
||||
}
|
||||
});
|
||||
|
||||
String[] currencyFullname = new String[currencyNames.length];
|
||||
|
||||
for(int i = 0; i < currencyFullname.length; i++)
|
||||
@ -70,11 +74,58 @@ public class CurrencySelectionActivity extends AppCompatActivity {
|
||||
currencyArrayList.add(new Currency(currencyNames[i], currencySymbols[i]));
|
||||
}
|
||||
|
||||
CurrencyAdapter adapter = new CurrencyAdapter(this, currencyArrayList);
|
||||
adapter = new CurrencyAdapter(this, currencyArrayList);
|
||||
}
|
||||
|
||||
private void setupList()
|
||||
{
|
||||
listView = findViewById(R.id.coinsPreview);
|
||||
|
||||
listView.setAdapter(adapter);
|
||||
listView.setTextFilterEnabled(false);
|
||||
|
||||
filter = adapter.getFilter();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu)
|
||||
{
|
||||
/*final AutoCompleteTextView searchAutoComplete = findViewById(R.id.search_bar);
|
||||
|
||||
searchAutoComplete.setOnItemClickListener(new AdapterView.OnItemClickListener() {
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
|
||||
Currency selectedCurrency = (Currency) adapterView.getItemAtPosition(i);
|
||||
Intent intent = new Intent(CurrencySelectionActivity.this, RecordTransactionActivity.class);
|
||||
intent.putExtra("coin", selectedCurrency.getName());
|
||||
intent.putExtra("symbol", selectedCurrency.getSymbol());
|
||||
startActivity(intent);
|
||||
finish();
|
||||
}
|
||||
});
|
||||
|
||||
searchAutoComplete.setAdapter(adapter);
|
||||
searchAutoComplete.setThreshold(0);
|
||||
searchAutoComplete.setThreshold(0);*/
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onQueryTextChange(String text)
|
||||
{
|
||||
filter.filter(text);
|
||||
|
||||
if (TextUtils.isEmpty(text)) {
|
||||
listView.clearTextFilter();
|
||||
} else {
|
||||
listView.setFilterText(text);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onQueryTextSubmit(String query)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,10 @@
|
||||
package com.nauk.coinfolio.Activities;
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.app.Fragment;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
@ -13,22 +13,21 @@ import android.support.annotation.NonNull;
|
||||
import android.support.design.widget.AppBarLayout;
|
||||
import android.support.design.widget.BottomNavigationView;
|
||||
import android.support.design.widget.CollapsingToolbarLayout;
|
||||
import android.support.design.widget.CoordinatorLayout;
|
||||
import android.support.design.widget.FloatingActionButton;
|
||||
import android.support.design.widget.Snackbar;
|
||||
import android.support.v4.widget.NestedScrollView;
|
||||
import android.support.v4.widget.SwipeRefreshLayout;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.support.v7.graphics.Palette;
|
||||
import android.support.v7.widget.Toolbar;
|
||||
import android.util.Log;
|
||||
import android.view.Gravity;
|
||||
import android.view.View;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.Window;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.ProgressBar;
|
||||
@ -40,8 +39,8 @@ import com.luseen.spacenavigation.SpaceNavigationView;
|
||||
import com.luseen.spacenavigation.SpaceOnClickListener;
|
||||
import com.nauk.coinfolio.DataManagers.BalanceManager;
|
||||
import com.nauk.coinfolio.DataManagers.CurrencyData.Currency;
|
||||
import com.nauk.coinfolio.LayoutManagers.HomeLayoutGenerator;
|
||||
import com.nauk.coinfolio.DataManagers.PreferencesManager;
|
||||
import com.nauk.coinfolio.LayoutManagers.HomeLayoutGenerator;
|
||||
import com.nauk.coinfolio.R;
|
||||
|
||||
import java.io.IOException;
|
||||
@ -79,6 +78,7 @@ public class HomeActivity extends AppCompatActivity {
|
||||
private Dialog loadingDialog;
|
||||
private Handler handler;
|
||||
private Runnable updateRunnable;
|
||||
private ViewFlipper viewFlipper;
|
||||
|
||||
private BottomNavigationView.OnNavigationItemSelectedListener mOnNavigationItemSelectedListener
|
||||
= new BottomNavigationView.OnNavigationItemSelectedListener() {
|
||||
@ -148,6 +148,8 @@ public class HomeActivity extends AppCompatActivity {
|
||||
toolbarLayout = findViewById(R.id.toolbar_layout);
|
||||
toolbarSubtitle = findViewById(R.id.toolbarSubtitle);
|
||||
currencyLayout = findViewById(R.id.currencyListLayout);
|
||||
viewFlipper = findViewById(R.id.viewFlipperSummary);
|
||||
viewFlipper.setDisplayedChild(1);
|
||||
|
||||
ImageButton addCurrencyButton = findViewById(R.id.floatingAddButton);
|
||||
ImageButton detailsButton = findViewById(R.id.switch_button);
|
||||
@ -160,11 +162,11 @@ public class HomeActivity extends AppCompatActivity {
|
||||
|
||||
toolbarSubtitle.setText("US$0.00");
|
||||
|
||||
BottomNavigationView navigation = (BottomNavigationView) findViewById(R.id.navigation_home);
|
||||
/*BottomNavigationView navigation = (BottomNavigationView) findViewById(R.id.navigation_home);
|
||||
navigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener);
|
||||
navigation.setSelectedItemId(R.id.navigation_view_list);
|
||||
navigation.setFitsSystemWindows(true);
|
||||
navigation.setItemBackgroundResource(R.color.colorAccent);
|
||||
navigation.setItemBackgroundResource(R.color.colorAccent);*/
|
||||
|
||||
//Events setup
|
||||
detailsButton.setOnClickListener(new View.OnClickListener() {
|
||||
@ -223,7 +225,6 @@ public class HomeActivity extends AppCompatActivity {
|
||||
spaceNavigationView.addSpaceItem(new SpaceItem("Charts", R.drawable.ic_show_chart_black_24dp));
|
||||
spaceNavigationView.addSpaceItem(new SpaceItem("Market Cap.", R.drawable.ic_pie_chart_black_24dp));
|
||||
spaceNavigationView.setSpaceBackgroundColor(getResources().getColor(R.color.colorPrimary));
|
||||
//spaceNavigationView.setCentreButtonIcon(R.drawable.ic_add_white_24dp);
|
||||
spaceNavigationView.setCentreButtonIcon(R.drawable.ic_view_list_white_24dp);
|
||||
spaceNavigationView.setCentreButtonColor(getResources().getColor(R.color.colorAccent));
|
||||
spaceNavigationView.setCentreButtonIconColorFilterEnabled(false);
|
||||
@ -237,8 +238,13 @@ public class HomeActivity extends AppCompatActivity {
|
||||
SpaceNavigationView nav = findViewById(R.id.space);
|
||||
|
||||
nav.changeCurrentItem(-1);
|
||||
((AppBarLayout) findViewById(R.id.app_bar)).setNestedScrollingEnabled(true);
|
||||
|
||||
((NestedScrollView) findViewById(R.id.nestedScrollViewLayout)).setNestedScrollingEnabled(true);
|
||||
((AppBarLayout) findViewById(R.id.app_bar)).setExpanded(true, true);
|
||||
|
||||
findViewById(R.id.switch_button).setVisibility(View.VISIBLE);
|
||||
|
||||
viewFlipper.setDisplayedChild(1);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -248,9 +254,14 @@ public class HomeActivity extends AppCompatActivity {
|
||||
|
||||
//0 : Unknown
|
||||
//1 : Market cap
|
||||
((AppBarLayout) findViewById(R.id.app_bar)).setNestedScrollingEnabled(false);
|
||||
((NestedScrollView) findViewById(R.id.nestedScrollViewLayout)).setNestedScrollingEnabled(false);
|
||||
((AppBarLayout) findViewById(R.id.app_bar)).setExpanded(false, true);
|
||||
|
||||
findViewById(R.id.switch_button).setVisibility(View.GONE);
|
||||
|
||||
|
||||
|
||||
viewFlipper.setDisplayedChild(itemIndex * 2);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -394,7 +405,9 @@ public class HomeActivity extends AppCompatActivity {
|
||||
result = BitmapFactory.decodeStream(input);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
result = null;
|
||||
result = BitmapFactory.decodeResource(this.getResources(),
|
||||
R.mipmap.icon_coinfolio);
|
||||
result = Bitmap.createScaledBitmap(result, 50, 50, false);
|
||||
}
|
||||
|
||||
callBack.onSuccess(result);
|
||||
@ -470,7 +483,7 @@ public class HomeActivity extends AppCompatActivity {
|
||||
|
||||
if(balanceManager.getTotalBalance() != null)
|
||||
{
|
||||
if(coinCounter == balanceManager.getTotalBalance().size())
|
||||
if(coinCounter == balanceManager.getTotalBalance().size() && detailsChecker)
|
||||
{
|
||||
for (int i = 0; i < balanceManager.getTotalBalance().size(); i++)
|
||||
{
|
||||
@ -502,6 +515,8 @@ public class HomeActivity extends AppCompatActivity {
|
||||
{
|
||||
ImageButton imgButton = findViewById(R.id.switch_button);
|
||||
|
||||
imgButton.setBackgroundColor(this.getResources().getColor(R.color.buttonColor));
|
||||
|
||||
if(isDetailed)
|
||||
{
|
||||
imgButton.setBackground(this.getResources().getDrawable(R.drawable.ic_unfold_less_black_24dp));
|
||||
@ -517,6 +532,7 @@ public class HomeActivity extends AppCompatActivity {
|
||||
private void generateSplash()
|
||||
{
|
||||
LinearLayout loadingLayout = new LinearLayout(this);
|
||||
|
||||
loadingLayout.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
|
||||
loadingLayout.setGravity(Gravity.CENTER);
|
||||
loadingLayout.setOrientation(LinearLayout.VERTICAL);
|
||||
@ -683,6 +699,14 @@ public class HomeActivity extends AppCompatActivity {
|
||||
@Override
|
||||
protected Void doInBackground(Void... params)
|
||||
{
|
||||
balanceManager.updateDetails(new BalanceManager.IconCallBack() {
|
||||
@Override
|
||||
public void onSuccess()
|
||||
{
|
||||
countCoins(false, true);
|
||||
}
|
||||
});
|
||||
|
||||
balanceManager.updateTotalBalance(new BalanceManager.VolleyCallBack() {
|
||||
@Override
|
||||
public void onSuccess() {
|
||||
@ -731,14 +755,6 @@ public class HomeActivity extends AppCompatActivity {
|
||||
}
|
||||
});
|
||||
|
||||
balanceManager.updateDetails(new BalanceManager.IconCallBack() {
|
||||
@Override
|
||||
public void onSuccess()
|
||||
{
|
||||
countCoins(false, true);
|
||||
}
|
||||
});
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
package com.nauk.coinfolio.Activities;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.os.Bundle;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
import android.widget.TextView;
|
||||
|
@ -12,10 +12,10 @@ import android.os.Bundle;
|
||||
import android.preference.ListPreference;
|
||||
import android.preference.Preference;
|
||||
import android.preference.PreferenceActivity;
|
||||
import android.support.v7.app.ActionBar;
|
||||
import android.preference.PreferenceFragment;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.preference.RingtonePreference;
|
||||
import android.support.v7.app.ActionBar;
|
||||
import android.text.TextUtils;
|
||||
import android.view.MenuItem;
|
||||
|
||||
|
@ -12,6 +12,10 @@ import com.android.volley.VolleyError;
|
||||
import com.android.volley.toolbox.JsonArrayRequest;
|
||||
import com.android.volley.toolbox.StringRequest;
|
||||
import com.android.volley.toolbox.Volley;
|
||||
import com.binance.api.client.BinanceApiClientFactory;
|
||||
import com.binance.api.client.BinanceApiRestClient;
|
||||
import com.binance.api.client.domain.account.Account;
|
||||
import com.binance.api.client.domain.account.AssetBalance;
|
||||
import com.nauk.coinfolio.DataManagers.CurrencyData.Currency;
|
||||
import com.nauk.coinfolio.R;
|
||||
|
||||
@ -21,6 +25,7 @@ import org.json.JSONObject;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Pattern;
|
||||
@ -39,24 +44,24 @@ public class BalanceManager {
|
||||
private String privatePoloniex;
|
||||
final private String hitBalanceUrl = "https://api.hitbtc.com/api/2/trading/balance";
|
||||
final private String detailUrl = "https://www.cryptocompare.com/api/data/coinlist/";
|
||||
final private String binanceBalanceUrl = "https://api.binance.com/api/v3/account";
|
||||
final private String binanceTimeUrl = "https://api.binance.com/api/v1/time";
|
||||
private RequestQueue requestQueue;
|
||||
private List<Currency> binanceBalance;
|
||||
private List<Currency> hitBalance;
|
||||
private List<Currency> manualBalances;
|
||||
private List<Currency> totalBalance;
|
||||
private android.content.Context context;
|
||||
private Map<String, String> iconUrlList;
|
||||
private Map<String, String> coinList;
|
||||
private Map<String, Integer> coinIdList;
|
||||
private LinkedHashMap<String, String> coinInfosHashmap;
|
||||
private PreferencesManager preferenceManager;
|
||||
private DatabaseManager databaseManager;
|
||||
|
||||
private BinanceApiClientFactory binanceApiClientFactory;
|
||||
|
||||
public BalanceManager(android.content.Context context)
|
||||
{
|
||||
this.context = context;
|
||||
preferenceManager = new PreferencesManager(context);
|
||||
requestQueue = Volley.newRequestQueue(context);
|
||||
binanceBalance = new ArrayList<Currency>();
|
||||
hitBalance = new ArrayList<Currency>();
|
||||
manualBalances = new ArrayList<Currency>();
|
||||
databaseManager = new DatabaseManager(context);
|
||||
@ -64,18 +69,62 @@ public class BalanceManager {
|
||||
|
||||
public List<String> getCurrenciesName()
|
||||
{
|
||||
return new ArrayList<>(coinList.values());
|
||||
List<String> currenciesName = new ArrayList<>();
|
||||
|
||||
for (String symbol : coinInfosHashmap.keySet())
|
||||
{
|
||||
try {
|
||||
JSONObject jsonObject = new JSONObject(coinInfosHashmap.get(symbol));
|
||||
currenciesName.add(jsonObject.getString("CoinName"));
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
return currenciesName;
|
||||
}
|
||||
|
||||
public List<String> getOrders()
|
||||
{
|
||||
List<String> currenciesOrder = new ArrayList<>();
|
||||
|
||||
for(String symbol : coinInfosHashmap.keySet())
|
||||
{
|
||||
try {
|
||||
JSONObject jsonObject = new JSONObject(coinInfosHashmap.get(symbol));
|
||||
currenciesOrder.add(jsonObject.getString("SortOrder"));
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
return currenciesOrder;
|
||||
}
|
||||
|
||||
public List<String> getCurrenciesSymbol()
|
||||
{
|
||||
return new ArrayList<>(coinList.keySet());
|
||||
return new ArrayList<>(coinInfosHashmap.keySet());
|
||||
}
|
||||
|
||||
public void updateExchangeKeys()
|
||||
{
|
||||
publicHitKey = preferenceManager.getHitBTCPublicKey();
|
||||
privateHitKey = preferenceManager.getHitBTCPrivateKey();
|
||||
|
||||
publicBinanceKey = preferenceManager.getBinancePublicKey();
|
||||
privateBinanceKey = preferenceManager.getBinancePrivateKey();
|
||||
}
|
||||
|
||||
public boolean isBinanceConfigured()
|
||||
{
|
||||
boolean isConfigured = true;
|
||||
|
||||
if(publicBinanceKey == null || privateBinanceKey == null)
|
||||
{
|
||||
isConfigured = false;
|
||||
}
|
||||
|
||||
return isConfigured;
|
||||
}
|
||||
|
||||
public boolean isHitBTCConfigured()
|
||||
@ -117,19 +166,61 @@ public class BalanceManager {
|
||||
|
||||
public void updateTotalBalance(final VolleyCallBack callBack)
|
||||
{
|
||||
boolean isUpdated = false;
|
||||
manualBalances = databaseManager.getAllCurrencyFromManualCurrency();
|
||||
|
||||
Log.d("coinfolio", "Updating balances " + (privateBinanceKey != null && publicBinanceKey != null && preferenceManager.isBinanceActivated()));
|
||||
|
||||
if(privateHitKey != null && publicHitKey != null && preferenceManager.isHitBTCActivated())
|
||||
{
|
||||
updateHitBalance(callBack);
|
||||
isUpdated = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
hitBalance = new ArrayList<Currency>();
|
||||
}
|
||||
|
||||
if(privateBinanceKey != null && publicBinanceKey != null && preferenceManager.isBinanceActivated())
|
||||
{
|
||||
Log.d("coinfolio", "Updating Binance");
|
||||
updateBinanceBalance();
|
||||
isUpdated = true;
|
||||
}
|
||||
|
||||
if(!isUpdated)
|
||||
{
|
||||
refreshAllBalances(callBack);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateBinanceBalance()
|
||||
{
|
||||
Map<String, AssetBalance> accountBalanceCache;
|
||||
BinanceApiClientFactory factory = BinanceApiClientFactory.newInstance(publicBinanceKey, privateBinanceKey);
|
||||
BinanceApiRestClient client = factory.newRestClient();
|
||||
|
||||
Account account = client.getAccount();
|
||||
List<AssetBalance> assets = account.getBalances();
|
||||
|
||||
binanceBalance = new ArrayList<Currency>();
|
||||
|
||||
for(int i = 0; i < assets.size(); i++)
|
||||
{
|
||||
if(Double.parseDouble(assets.get(i).getFree()) > 0)
|
||||
{
|
||||
binanceBalance.add(new Currency(assets.get(i).getAsset(), assets.get(i).getFree()));
|
||||
}
|
||||
}
|
||||
|
||||
Log.d("coinfolio", "Binance size : " + binanceBalance.size());
|
||||
|
||||
for(int i = 0; i < binanceBalance.size(); i++)
|
||||
{
|
||||
Log.d("coinfolio", "Binance : " + binanceBalance.get(i).getSymbol() + " " + binanceBalance.get(i).getBalance());
|
||||
}
|
||||
}
|
||||
|
||||
private void updateHitBalance(final VolleyCallBack callBack)
|
||||
{
|
||||
JsonArrayRequest arrReq = new JsonArrayRequest(Request.Method.GET, hitBalanceUrl,
|
||||
@ -269,10 +360,14 @@ public class BalanceManager {
|
||||
String url;
|
||||
|
||||
try {
|
||||
url = iconUrlList.get(symbol);
|
||||
JSONObject jsonObject = new JSONObject(coinInfosHashmap.get(symbol));
|
||||
url = "https://www.cryptocompare.com" + jsonObject.getString("ImageUrl") + "?width=50";
|
||||
} catch (NullPointerException e) {
|
||||
Log.d(context.getResources().getString(R.string.debug), symbol + " has no icon URL");
|
||||
url = null;
|
||||
} catch (JSONException e) {
|
||||
Log.d(context.getResources().getString(R.string.debug), "Url parsing error for " + symbol);
|
||||
url = null;
|
||||
}
|
||||
|
||||
return url;
|
||||
@ -280,12 +375,30 @@ public class BalanceManager {
|
||||
|
||||
public String getCurrencyName(String symbol)
|
||||
{
|
||||
return coinList.get(symbol);
|
||||
String currencyName = null;
|
||||
|
||||
try {
|
||||
JSONObject jsonObject = new JSONObject(coinInfosHashmap.get(symbol));
|
||||
currencyName = jsonObject.getString("CoinName");
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return currencyName;
|
||||
}
|
||||
|
||||
public int getCurrencyId(String symbol)
|
||||
{
|
||||
return coinIdList.get(symbol);
|
||||
int id = 0;
|
||||
|
||||
try {
|
||||
JSONObject jsonObject = new JSONObject(coinInfosHashmap.get(symbol));
|
||||
id = jsonObject.getInt("Id");
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
private void processDetailResult(String response, final IconCallBack callBack)
|
||||
@ -293,9 +406,7 @@ public class BalanceManager {
|
||||
response = response.substring(response.indexOf("\"Data\"") + 7, response.lastIndexOf("},\"Type\":100}"));
|
||||
String[] tab = response.split(Pattern.quote("},"));
|
||||
|
||||
iconUrlList = new HashMap<>();
|
||||
coinList = new HashMap<>();
|
||||
coinIdList = new HashMap<>();
|
||||
coinInfosHashmap = new LinkedHashMap<>();
|
||||
|
||||
for(int i = 0; i < tab.length; i++)
|
||||
{
|
||||
@ -305,16 +416,42 @@ public class BalanceManager {
|
||||
StrictMode.setThreadPolicy(policy);
|
||||
JSONObject jsonObject = new JSONObject(tab[i]);
|
||||
|
||||
iconUrlList.put(jsonObject.getString("Symbol"), "https://www.cryptocompare.com" + jsonObject.getString("ImageUrl") + "?width=50");
|
||||
|
||||
coinList.put(jsonObject.getString("Symbol"), jsonObject.getString("CoinName"));
|
||||
|
||||
coinIdList.put(jsonObject.getString("Symbol"), jsonObject.getInt("Id"));
|
||||
coinInfosHashmap.put(jsonObject.getString("Symbol"), tab[i]);
|
||||
} catch (JSONException e) {
|
||||
Log.d(context.getResources().getString(R.string.debug), "ImageUrl not found.");
|
||||
}
|
||||
}
|
||||
|
||||
sortDetails();
|
||||
|
||||
callBack.onSuccess();
|
||||
}
|
||||
|
||||
private void sortDetails()
|
||||
{
|
||||
LinkedHashMap<String, String> sortedHashmap = new LinkedHashMap<>();
|
||||
List<String> listInfos = new ArrayList<>(coinInfosHashmap.values());
|
||||
List<String> listSymbols = new ArrayList<>(coinInfosHashmap.keySet());
|
||||
|
||||
for(int i = 0; i < coinInfosHashmap.keySet().size(); i++)
|
||||
{
|
||||
|
||||
try {
|
||||
JSONObject jsonObject = new JSONObject(listInfos.get(i));
|
||||
int index = jsonObject.getInt("SortOrder");
|
||||
|
||||
listInfos.add(index, listInfos.get(i));
|
||||
listSymbols.add(index, listSymbols.get(i));
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
for(int i = 0; i < listInfos.size(); i++)
|
||||
{
|
||||
sortedHashmap.put(listSymbols.get(i), listInfos.get(i));
|
||||
}
|
||||
|
||||
coinInfosHashmap = sortedHashmap;
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,6 @@ package com.nauk.coinfolio.DataManagers.CurrencyData;
|
||||
import android.graphics.Bitmap;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
@ -5,13 +5,11 @@ import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.database.sqlite.SQLiteOpenHelper;
|
||||
import android.util.Log;
|
||||
|
||||
import com.nauk.coinfolio.DataManagers.CurrencyData.Currency;
|
||||
import com.nauk.coinfolio.DataManagers.CurrencyData.Transaction;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
|
@ -65,4 +65,25 @@ public class PreferencesManager {
|
||||
editor.apply();
|
||||
}
|
||||
|
||||
public String getBinancePublicKey()
|
||||
{
|
||||
return settingPreferences.getString("binance_publickey", null);
|
||||
}
|
||||
|
||||
public String getBinancePrivateKey()
|
||||
{
|
||||
return settingPreferences.getString("binance_privatekey", null);
|
||||
}
|
||||
|
||||
public boolean isBinanceActivated()
|
||||
{
|
||||
return settingPreferences.getBoolean("enable_binance", false);
|
||||
}
|
||||
|
||||
public void disableBinance()
|
||||
{
|
||||
SharedPreferences.Editor editor = settingPreferences.edit();
|
||||
editor.putBoolean("enable_binance", false);
|
||||
editor.apply();
|
||||
}
|
||||
}
|
||||
|
@ -8,11 +8,11 @@ import android.widget.ArrayAdapter;
|
||||
import android.widget.Filter;
|
||||
import android.widget.TextView;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import com.nauk.coinfolio.DataManagers.CurrencyData.Currency;
|
||||
import com.nauk.coinfolio.R;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* Created by Guitoune on 17/01/2018.
|
||||
*/
|
||||
@ -46,9 +46,9 @@ public class CurrencyAdapter extends ArrayAdapter<Currency> {
|
||||
}
|
||||
// Now assign alternate color for rows
|
||||
if (position % 2 == 0)
|
||||
convertView.setBackgroundColor(context.getResources().getColor(R.color.listBackground));
|
||||
else
|
||||
convertView.setBackgroundColor(context.getResources().getColor(R.color.listBackground2));
|
||||
else
|
||||
convertView.setBackgroundColor(context.getResources().getColor(R.color.listBackground));
|
||||
|
||||
return convertView;
|
||||
}
|
||||
@ -70,13 +70,28 @@ public class CurrencyAdapter extends ArrayAdapter<Currency> {
|
||||
if (constraint != null) {
|
||||
suggestions.clear();
|
||||
|
||||
int i = 0;
|
||||
int found = 0;
|
||||
String temp = constraint.toString().toLowerCase();
|
||||
for (Currency currency : tempCurrency) {
|
||||
|
||||
while(i < tempCurrency.size() && found < 25)
|
||||
{
|
||||
Currency currency = tempCurrency.get(i);
|
||||
if (currency.getName().toLowerCase().startsWith(temp)
|
||||
|| currency.getSymbol().toLowerCase().startsWith(temp)) {
|
||||
suggestions.add(currency);
|
||||
found++;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
|
||||
/*for (Currency currency : tempCurrency) {
|
||||
if (currency.getName().toLowerCase().startsWith(temp)
|
||||
|| currency.getSymbol().toLowerCase().startsWith(temp)) {
|
||||
suggestions.add(currency);
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
FilterResults filterResults = new FilterResults();
|
||||
filterResults.values = suggestions;
|
||||
|
@ -1,20 +1,13 @@
|
||||
package com.nauk.coinfolio.LayoutManagers;
|
||||
|
||||
import android.animation.AnimatorInflater;
|
||||
import android.animation.StateListAnimator;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.PorterDuffColorFilter;
|
||||
import android.support.v7.widget.CardView;
|
||||
import android.util.Log;
|
||||
import android.view.Gravity;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.db.chart.model.ChartSet;
|
||||
@ -26,18 +19,12 @@ import com.nauk.coinfolio.DataManagers.CurrencyData.Currency;
|
||||
import com.nauk.coinfolio.DataManagers.CurrencyData.CurrencyDataChart;
|
||||
import com.nauk.coinfolio.R;
|
||||
|
||||
import org.w3c.dom.Text;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import static java.lang.Math.abs;
|
||||
import static java.lang.Math.floorDiv;
|
||||
import static java.lang.Math.floorMod;
|
||||
import static java.lang.Math.incrementExact;
|
||||
import static java.sql.Types.NULL;
|
||||
|
||||
/**
|
||||
* Created by Tiji on 05/01/2018.
|
||||
|
@ -1,13 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item>
|
||||
<shape>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle" >
|
||||
<gradient
|
||||
android:angle="0"
|
||||
android:startColor="@color/colorPrimary"
|
||||
android:endColor="@color/colorAccent"
|
||||
android:type="linear"/>
|
||||
</shape>
|
||||
</item>
|
||||
|
||||
</selector>
|
||||
android:type="linear"
|
||||
android:centerX="60%"
|
||||
android:startColor="#FF1CB5E0"
|
||||
android:centerColor="#FF000046"
|
||||
android:endColor="#FF111124"
|
||||
android:angle="90"/>
|
||||
</shape>
|
@ -4,6 +4,6 @@
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="@color/listBackground"
|
||||
android:fillColor="@color/buttonColor"
|
||||
android:pathData="M3,4l9,16 9,-16L3,4zM6.38,6h11.25L12,16 6.38,6z"/>
|
||||
</vector>
|
||||
|
@ -4,6 +4,6 @@
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="@color/listBackground"
|
||||
android:fillColor="@color/buttonColor"
|
||||
android:pathData="M19.43,12.98c0.04,-0.32 0.07,-0.64 0.07,-0.98s-0.03,-0.66 -0.07,-0.98l2.11,-1.65c0.19,-0.15 0.24,-0.42 0.12,-0.64l-2,-3.46c-0.12,-0.22 -0.39,-0.3 -0.61,-0.22l-2.49,1c-0.52,-0.4 -1.08,-0.73 -1.69,-0.98l-0.38,-2.65C14.46,2.18 14.25,2 14,2h-4c-0.25,0 -0.46,0.18 -0.49,0.42l-0.38,2.65c-0.61,0.25 -1.17,0.59 -1.69,0.98l-2.49,-1c-0.23,-0.09 -0.49,0 -0.61,0.22l-2,3.46c-0.13,0.22 -0.07,0.49 0.12,0.64l2.11,1.65c-0.04,0.32 -0.07,0.65 -0.07,0.98s0.03,0.66 0.07,0.98l-2.11,1.65c-0.19,0.15 -0.24,0.42 -0.12,0.64l2,3.46c0.12,0.22 0.39,0.3 0.61,0.22l2.49,-1c0.52,0.4 1.08,0.73 1.69,0.98l0.38,2.65c0.03,0.24 0.24,0.42 0.49,0.42h4c0.25,0 0.46,-0.18 0.49,-0.42l0.38,-2.65c0.61,-0.25 1.17,-0.59 1.69,-0.98l2.49,1c0.23,0.09 0.49,0 0.61,-0.22l2,-3.46c0.12,-0.22 0.07,-0.49 -0.12,-0.64l-2.11,-1.65zM12,15.5c-1.93,0 -3.5,-1.57 -3.5,-3.5s1.57,-3.5 3.5,-3.5 3.5,1.57 3.5,3.5 -1.57,3.5 -3.5,3.5z"/>
|
||||
</vector>
|
||||
|
@ -4,6 +4,6 @@
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="@color/listBackground"
|
||||
android:fillColor="@color/buttonColor"
|
||||
android:pathData="M7.41,18.59L8.83,20 12,16.83 15.17,20l1.41,-1.41L12,14l-4.59,4.59zM16.59,5.41L15.17,4 12,7.17 8.83,4 7.41,5.41 12,10l4.59,-4.59z"/>
|
||||
</vector>
|
||||
|
@ -1,6 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
@ -10,22 +9,21 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@drawable/soft_gradient"
|
||||
android:gravity="center">
|
||||
android:gravity="center_horizontal"
|
||||
android:orientation="vertical">
|
||||
|
||||
<!--<EditText
|
||||
android:layout_width="200dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:background="@drawable/rounded_corners"/>-->
|
||||
|
||||
<AutoCompleteTextView
|
||||
<SearchView
|
||||
android:id="@+id/search_bar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center|top"
|
||||
android:padding="15dp"
|
||||
android:background="@color/listBackground"/>
|
||||
|
||||
<ListView
|
||||
android:id="@+id/coinsPreview"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</android.support.constraint.ConstraintLayout>
|
||||
|
@ -44,8 +44,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
app:layout_collapseMode="pin"
|
||||
app:popupTheme="@style/AppTheme.PopupOverlay"
|
||||
android:background="@drawable/gradient_background">
|
||||
app:popupTheme="@style/AppTheme.PopupOverlay">
|
||||
|
||||
</android.support.v7.widget.Toolbar>
|
||||
|
||||
@ -61,7 +60,8 @@
|
||||
android:id="@+id/switch_button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/quick_button"/>
|
||||
android:text="@string/quick_button"
|
||||
android:visibility="visible"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
@ -77,7 +77,8 @@
|
||||
android:id="@+id/settings_button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/action_settings" />
|
||||
android:text="@string/action_settings"
|
||||
android:visibility="visible"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
@ -86,7 +87,7 @@
|
||||
|
||||
<include layout="@layout/content_currency_summary" />
|
||||
|
||||
<android.support.design.widget.BottomNavigationView
|
||||
<!--<android.support.design.widget.BottomNavigationView
|
||||
android:id="@+id/navigation_home"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
@ -99,7 +100,7 @@
|
||||
app:menu="@menu/navigation_home"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_gravity="bottom"
|
||||
android:visibility="gone"/>
|
||||
android:visibility="gone"/>-->
|
||||
|
||||
<com.luseen.spacenavigation.SpaceNavigationView
|
||||
android:id="@+id/space"
|
||||
|
@ -1,6 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
|
@ -1,6 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
@ -13,6 +12,7 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="10dp"
|
||||
android:clickable="false"
|
||||
android:backgroundTint="@color/listBackground2"
|
||||
app:cardCornerRadius="8dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent">
|
||||
|
||||
|
@ -4,11 +4,39 @@
|
||||
android:id="@+id/swiperefresh"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior">
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior"
|
||||
android:layout_marginBottom="50dp">
|
||||
|
||||
<ViewFlipper
|
||||
android:id="@+id/viewFlipperSummary"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/progressBarWatchlist"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
style="?android:attr/progressBarStyleLarge"
|
||||
android:layout_gravity="center"
|
||||
android:background="@drawable/circular_progress_bar" />
|
||||
|
||||
<!--<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Watch list"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:gravity="center_horizontal"/>-->
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<android.support.v4.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/nestedScrollViewLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context="com.nauk.coinfolio.Activities.HomeActivity"
|
||||
@ -35,4 +63,35 @@
|
||||
|
||||
</android.support.v4.widget.NestedScrollView>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<!--<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Market cap"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:gravity="center_horizontal"/>-->
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/layoutProgressMarketCap"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:visibility="visible">
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/progressBarMarketCap"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
style="?android:attr/progressBarStyleLarge"
|
||||
android:layout_gravity="center"
|
||||
android:background="@drawable/circular_progress_bar" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</ViewFlipper>
|
||||
|
||||
</android.support.v4.widget.SwipeRefreshLayout>
|
@ -1,4 +1,23 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
<resources>
|
||||
<color name="colorPrimary">#093e93</color>
|
||||
<color name="colorPrimaryDark">#000046</color>
|
||||
<color name="colorAccent">#1cb5e0</color>
|
||||
<color name="mainTextViewColor">#FFFFFFFF</color>
|
||||
<color name="secondaryTextViewColor">#FFDDDDDD</color>
|
||||
<color name="transparent">#00000000</color>
|
||||
<color name="decrease">#FFED143D</color>
|
||||
<color name="increase">#FF00E000</color>
|
||||
<color name="buttonColor">#FFFFFFFF</color>
|
||||
<color name="listBackground">#000046</color>
|
||||
<color name="listBackground2">#000046</color>
|
||||
<color name="separationLine">#FF999999</color>
|
||||
<color name="red">#FFF44336</color>
|
||||
<color name="green">#FF4CAF50</color>
|
||||
</resources>
|
||||
-->
|
||||
|
||||
<resources>
|
||||
<color name="colorPrimary">#000046</color>
|
||||
<color name="colorPrimaryDark">#111124</color>
|
||||
@ -11,6 +30,7 @@
|
||||
<color name="listBackground">#FFEEEEEE</color>
|
||||
<color name="listBackground2">#FFFFFFFF</color>
|
||||
<color name="separationLine">#FF999999</color>
|
||||
<color name="buttonColor">#FFFFFFFF</color>
|
||||
<color name="red">#FFF44336</color>
|
||||
<color name="green">#FF4CAF50</color>
|
||||
</resources>
|
@ -59,7 +59,7 @@
|
||||
|
||||
<PreferenceCategory
|
||||
android:title="@string/pref_title_exchange_binance"
|
||||
android:enabled="false">
|
||||
android:enabled="true">
|
||||
<SwitchPreference
|
||||
android:defaultValue="false"
|
||||
android:key="enable_binance"
|
||||
@ -79,7 +79,7 @@
|
||||
android:capitalize="words"
|
||||
android:dependency="enable_binance"
|
||||
android:inputType="text"
|
||||
android:key="binance_privatekey"
|
||||
android:key="binance_publickey"
|
||||
android:maxLines="1"
|
||||
android:selectAllOnFocus="true"
|
||||
android:singleLine="true"
|
||||
|
@ -2,7 +2,7 @@ package com.nauk.coinfolio;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
* Example local unit test, which will execute on the development machine (host).
|
||||
|
@ -10,6 +10,7 @@
|
||||
# Specifies the JVM arguments used for the daemon process.
|
||||
# The setting is particularly useful for tweaking memory settings.
|
||||
org.gradle.jvmargs=-Xmx1536m
|
||||
android.enableD8=true
|
||||
|
||||
# When configured, Gradle will run in incubating parallel mode.
|
||||
# This option should only be used with decoupled projects. More details, visit
|
||||
|
131
library/Binance/.gitignore
vendored
131
library/Binance/.gitignore
vendored
@ -1,131 +0,0 @@
|
||||
*.class
|
||||
|
||||
# Mobile Tools for Java (J2ME)
|
||||
.mtj.tmp/
|
||||
|
||||
# Package Files #
|
||||
*.jar
|
||||
*.war
|
||||
*.ear
|
||||
|
||||
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
|
||||
hs_err_pid*
|
||||
|
||||
# https://github.com/github/gitignore/blob/master/Scala.gitignore
|
||||
*.class
|
||||
*.log
|
||||
|
||||
# sbt specific
|
||||
.cache
|
||||
.history
|
||||
.lib/
|
||||
dist/*
|
||||
target/
|
||||
lib_managed/
|
||||
src_managed/
|
||||
project/boot/
|
||||
project/plugins/project/
|
||||
|
||||
# Scala-IDE specific
|
||||
.scala_dependencies
|
||||
.worksheet
|
||||
|
||||
**/.cache-main
|
||||
|
||||
# https://github.com/github/gitignore/blob/master/Global/Eclipse.gitignore
|
||||
.metadata
|
||||
bin/
|
||||
tmp/
|
||||
*.tmp
|
||||
*.bak
|
||||
*.swp
|
||||
*~.nib
|
||||
local.properties
|
||||
.settings/
|
||||
.loadpath
|
||||
.recommenders
|
||||
|
||||
# Eclipse Core
|
||||
.project
|
||||
.classpath
|
||||
|
||||
# External tool builders
|
||||
.externalToolBuilders/
|
||||
|
||||
# Locally stored "Eclipse launch configurations"
|
||||
*.launch
|
||||
|
||||
# PyDev specific (Python IDE for Eclipse)
|
||||
*.pydevproject
|
||||
|
||||
# CDT-specific (C/C++ Development Tooling)
|
||||
.cproject
|
||||
|
||||
# JDT-specific (Eclipse Java Development Tools)
|
||||
**/.classpath
|
||||
|
||||
# Java annotation processor (APT)
|
||||
.factorypath
|
||||
|
||||
# PDT-specific (PHP Development Tools)
|
||||
.buildpath
|
||||
|
||||
# sbteclipse plugin
|
||||
.target
|
||||
|
||||
# Tern plugin
|
||||
.tern-project
|
||||
|
||||
# TeXlipse plugin
|
||||
.texlipse
|
||||
|
||||
# STS (Spring Tool Suite)
|
||||
.springBeans
|
||||
|
||||
# Code Recommenders
|
||||
.recommenders/
|
||||
|
||||
# https://github.com/github/gitignore/blob/master/Global/JetBrains.gitignore
|
||||
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
|
||||
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
||||
|
||||
# IntelliJ
|
||||
.idea
|
||||
*.iml
|
||||
|
||||
# Mongo Explorer plugin:
|
||||
.idea/mongoSettings.xml
|
||||
|
||||
## File-based project format:
|
||||
*.iws
|
||||
|
||||
## Plugin-specific files:
|
||||
|
||||
# IntelliJ
|
||||
/out/
|
||||
|
||||
# mpeltonen/sbt-idea plugin
|
||||
.idea_modules/
|
||||
|
||||
# JIRA plugin
|
||||
atlassian-ide-plugin.xml
|
||||
|
||||
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||
com_crashlytics_export_strings.xml
|
||||
crashlytics.properties
|
||||
crashlytics-build.properties
|
||||
fabric.properties
|
||||
|
||||
# https://github.com/github/gitignore/blob/master/Maven.gitignore
|
||||
target/
|
||||
pom.xml.tag
|
||||
pom.xml.releaseBackup
|
||||
pom.xml.versionsBackup
|
||||
pom.xml.next
|
||||
release.properties
|
||||
dependency-reduced-pom.xml
|
||||
buildNumber.properties
|
||||
.mvn/timing.properties
|
||||
|
||||
# test
|
||||
test-output
|
@ -1,92 +0,0 @@
|
||||
# Contributing
|
||||
|
||||
When contributing to this repository, please first discuss the change you wish to make via issue,
|
||||
email, or any other method with the owners of this repository before making a change.
|
||||
|
||||
Please note we have a code of conduct, please follow it in all your interactions with the project.
|
||||
|
||||
## Pull Request Process
|
||||
|
||||
1. Ensure any install or build dependencies are removed before the end of the layer when doing a
|
||||
build.
|
||||
2. Update the README.md with details of changes to the interface, this includes new environment
|
||||
variables, exposed ports, useful file locations and container parameters.
|
||||
3. Increase the version numbers in any examples files and the README.md to the new version that this
|
||||
Pull Request would represent. The versioning scheme we use is [SemVer](http://semver.org/).
|
||||
4. You may merge the Pull Request in once you have the sign-off of two other developers, or if you
|
||||
do not have permission to do that, you may request the second reviewer to merge it for you.
|
||||
|
||||
## Code of Conduct
|
||||
|
||||
### Our Pledge
|
||||
|
||||
In the interest of fostering an open and welcoming environment, we as
|
||||
contributors and maintainers pledge to making participation in our project and
|
||||
our community a harassment-free experience for everyone, regardless of age, body
|
||||
size, disability, ethnicity, gender identity and expression, level of experience,
|
||||
nationality, personal appearance, race, religion, or sexual identity and
|
||||
orientation.
|
||||
|
||||
### Our Standards
|
||||
|
||||
Examples of behavior that contributes to creating a positive environment
|
||||
include:
|
||||
|
||||
* Using welcoming and inclusive language
|
||||
* Being respectful of differing viewpoints and experiences
|
||||
* Gracefully accepting constructive criticism
|
||||
* Focusing on what is best for the community
|
||||
* Showing empathy towards other community members
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
* The use of sexualized language or imagery and unwelcome sexual attention or
|
||||
advances
|
||||
* Trolling, insulting/derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or electronic
|
||||
address, without explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
### Our Responsibilities
|
||||
|
||||
Project maintainers are responsible for clarifying the standards of acceptable
|
||||
behavior and are expected to take appropriate and fair corrective action in
|
||||
response to any instances of unacceptable behavior.
|
||||
|
||||
Project maintainers have the right and responsibility to remove, edit, or
|
||||
reject comments, commits, code, wiki edits, issues, and other contributions
|
||||
that are not aligned to this Code of Conduct, or to ban temporarily or
|
||||
permanently any contributor for other behaviors that they deem inappropriate,
|
||||
threatening, offensive, or harmful.
|
||||
|
||||
### Scope
|
||||
|
||||
This Code of Conduct applies both within project spaces and in public spaces
|
||||
when an individual is representing the project or its community. Examples of
|
||||
representing a project or community include using an official project e-mail
|
||||
address, posting via an official social media account, or acting as an appointed
|
||||
representative at an online or offline event. Representation of a project may be
|
||||
further defined and clarified by project maintainers.
|
||||
|
||||
### Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported by contacting the project team. All
|
||||
complaints will be reviewed and investigated and will result in a response that
|
||||
is deemed necessary and appropriate to the circumstances. The project team is
|
||||
obligated to maintain confidentiality with regard to the reporter of an incident.
|
||||
Further details of specific enforcement policies may be posted separately.
|
||||
|
||||
Project maintainers who do not follow or enforce the Code of Conduct in good
|
||||
faith may face temporary or permanent repercussions as determined by other
|
||||
members of the project's leadership.
|
||||
|
||||
### Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
||||
available at [http://contributor-covenant.org/version/1/4][version]
|
||||
|
||||
[homepage]: http://contributor-covenant.org
|
||||
[version]: http://contributor-covenant.org/version/1/4/
|
@ -1,107 +0,0 @@
|
||||
# Java client for [Binance API](https://www.binance.com/restapipub.html)
|
||||
|
||||
## Synopsis
|
||||
Client for accessing Binance API using Java. An [async](src/main/java/com/github/johnsiu/binance/httpclients/AsyncBinanceClient.java) and a [sync](src/main/java/com/github/johnsiu/binance/httpclients/BinanceClient.java) versions of the client are available.
|
||||
|
||||
## Installation
|
||||
|
||||
Add the bintray repo to the pom of your maven project:
|
||||
|
||||
```xml
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>bintray-johnsiu-maven-repo</id>
|
||||
<url>https://dl.bintray.com/johnsiu/maven-repo</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
```
|
||||
then, add the dependency:
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>com.github.johnsiu</groupId>
|
||||
<artifactId>binance-java-client</artifactId>
|
||||
<version>1.0.1</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
### Creating an instance of the async client using Guice
|
||||
```java
|
||||
Injector injector = Guice.createInjector(new BinanceClientModule());
|
||||
AsyncBinanceClient asyncClient = injector.getInstance(AsyncBinanceClient.class);
|
||||
```
|
||||
### Creating an instance of the sync client using Guice
|
||||
```java
|
||||
Injector injector = Guice.createInjector(new BinanceClientModule());
|
||||
BinanceClient client = injector.getInstance(BinanceClient.class);
|
||||
```
|
||||
|
||||
### Getting latest price of a symbol
|
||||
```java
|
||||
Ticker ticker = client.getTicker("ETHBTC"));
|
||||
double price = ticker.getLastPrice();
|
||||
```
|
||||
### Getting depth of a symbol
|
||||
```java
|
||||
Depth depth = client.getDepth("ETHBTC"));
|
||||
```
|
||||
### Placing a LIMIT order
|
||||
```java
|
||||
Keys keys = new Keys("YOUR_API_KEY", "YOUR_SECRET_KEY");
|
||||
double quantity = 1;
|
||||
double price = 0.020041;
|
||||
Order order = client.placeLimitOrder(keys, "MCOETH", OrderSide.BUY, TimeInForce.GTC, quantity, price);
|
||||
```
|
||||
|
||||
### Placing a MARKET order
|
||||
```java
|
||||
double quantity = 1;
|
||||
Order order = client.placeMarketOrder(keys, "MCOETH", OrderSide.SELL, quantity);
|
||||
```
|
||||
### Checking an order’s status
|
||||
```java
|
||||
OrderStatus orderStatus = client.checkOrderStatus(keys, order);
|
||||
```
|
||||
|
||||
### Cancelling an order
|
||||
```java
|
||||
CancelOrder cancelOrder = client.cancelOrder(keys, order);
|
||||
// or
|
||||
CancelOrder cancelOrder = client.cancelOrder(keys, orderStatus);
|
||||
|
||||
```
|
||||
|
||||
### Getting a list of open orders
|
||||
```java
|
||||
List<OrderStatus> openOrders = client.getOpenOrders(keys, "MCOETH");
|
||||
```
|
||||
|
||||
### Getting a list of current position
|
||||
```java
|
||||
Account account = client.getAccount(keys);
|
||||
Map<String, Balance> balances = account.getBalances();
|
||||
```
|
||||
|
||||
### Exception handling
|
||||
```java
|
||||
try {
|
||||
Depth depth = client.getDepth("invalid symbol"));
|
||||
} catch (ClientErrorException e) {
|
||||
int httpStatusCode = e.getHttpStatusCode();
|
||||
String errorCode = e.getErrorDetails().getCode();
|
||||
String errorMessage = e.getErrorDetails().getMsg();
|
||||
}
|
||||
```
|
||||
|
||||
## Contributing
|
||||
|
||||
Please read [CONTRIBUTING.md](CONTRIBUTING.md) for details on our code of conduct, and the process for submitting pull requests to us.
|
||||
|
||||
## Versioning
|
||||
|
||||
We use [SemVer](http://semver.org/) for versioning. For the versions available, see the [tags on this repository](https://github.com/johnsiu/binance-java-client/tags).
|
||||
|
||||
## License
|
||||
|
||||
This project is released into the public domain - see the [UNLICENSE](UNLICENSE) file for details.
|
@ -1,24 +0,0 @@
|
||||
This is free and unencumbered software released into the public domain.
|
||||
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||
distribute this software, either in source code form or as a compiled
|
||||
binary, for any purpose, commercial or non-commercial, and by any
|
||||
means.
|
||||
|
||||
In jurisdictions that recognize copyright laws, the author or authors
|
||||
of this software dedicate any and all copyright interest in the
|
||||
software to the public domain. We make this dedication for the benefit
|
||||
of the public at large and to the detriment of our heirs and
|
||||
successors. We intend this dedication to be an overt act of
|
||||
relinquishment in perpetuity of all present and future rights to this
|
||||
software under copyright law.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
For more information, please refer to <http://unlicense.org/>
|
@ -1,83 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>com.github.johnsiu</groupId>
|
||||
<artifactId>binance-java-client</artifactId>
|
||||
<version>1.0.1</version>
|
||||
|
||||
<properties>
|
||||
<jackson-version>2.9.1</jackson-version>
|
||||
</properties>
|
||||
|
||||
<distributionManagement>
|
||||
<repository>
|
||||
<id>bintray-repo-binance-java-client</id>
|
||||
<url>https://api.bintray.com/maven/johnsiu/maven-repo/binance-java-client/;publish=1</url>
|
||||
</repository>
|
||||
</distributionManagement>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-source-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>attach-sources</id>
|
||||
<phase>verify</phase>
|
||||
<goals>
|
||||
<goal>jar-no-fork</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.asynchttpclient</groupId>
|
||||
<artifactId>async-http-client</artifactId>
|
||||
<version>2.0.37</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
<version>23.1-jre</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
<version>${jackson-version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.datatype</groupId>
|
||||
<artifactId>jackson-datatype-jsr310</artifactId>
|
||||
<version>${jackson-version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.inject</groupId>
|
||||
<artifactId>guice</artifactId>
|
||||
<version>4.1.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.12</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
@ -1,29 +0,0 @@
|
||||
package com.github.johnsiu.binance.deser;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.DeserializationContext;
|
||||
import com.fasterxml.jackson.databind.JsonDeserializer;
|
||||
import com.github.johnsiu.binance.models.Account.Balance;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableMap.Builder;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Jackson deserializer for turning an array of balances into a map of asset to balance.
|
||||
*/
|
||||
public class BalanceMapDeserializer extends JsonDeserializer<Map<String, Balance>> {
|
||||
|
||||
@Override
|
||||
public Map<String, Balance> deserialize(JsonParser p, DeserializationContext ctxt)
|
||||
throws IOException, JsonProcessingException {
|
||||
List<Balance> balances = p.readValueAs(new TypeReference<List<Balance>>() {
|
||||
});
|
||||
Builder<String, Balance> builder = ImmutableMap.<String, Balance>builder();
|
||||
balances.forEach(balance -> builder.put(balance.getAsset(), balance));
|
||||
return builder.build();
|
||||
}
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
package com.github.johnsiu.binance.exceptions;
|
||||
|
||||
import com.github.johnsiu.binance.models.ErrorDetails;
|
||||
|
||||
/**
|
||||
* Exception thrown when Binance API returned an HTTP 4xx client error.
|
||||
*/
|
||||
public class ClientErrorException extends RuntimeException {
|
||||
|
||||
private int httpStatusCode;
|
||||
// error message from Binance API.
|
||||
private ErrorDetails errorDetails;
|
||||
|
||||
public ClientErrorException(int httpStatusCode, ErrorDetails errorDetails) {
|
||||
super(errorDetails.getMsg());
|
||||
this.httpStatusCode = httpStatusCode;
|
||||
this.errorDetails = errorDetails;
|
||||
}
|
||||
|
||||
public int getHttpStatusCode() {
|
||||
return httpStatusCode;
|
||||
}
|
||||
|
||||
public ErrorDetails getErrorDetails() {
|
||||
return errorDetails;
|
||||
}
|
||||
}
|
@ -1,69 +0,0 @@
|
||||
package com.github.johnsiu.binance.httpclients;
|
||||
|
||||
import com.github.johnsiu.binance.models.Account;
|
||||
import com.github.johnsiu.binance.models.CancelOrder;
|
||||
import com.github.johnsiu.binance.models.Depth;
|
||||
import com.github.johnsiu.binance.models.Keys;
|
||||
import com.github.johnsiu.binance.models.Order;
|
||||
import com.github.johnsiu.binance.models.Order.OrderSide;
|
||||
import com.github.johnsiu.binance.models.Order.TimeInForce;
|
||||
import com.github.johnsiu.binance.models.OrderStatus;
|
||||
import com.github.johnsiu.binance.models.Ticker;
|
||||
import com.google.inject.ImplementedBy;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletionStage;
|
||||
|
||||
/**
|
||||
* Async client for accessing Binance API.
|
||||
*/
|
||||
@ImplementedBy(AsyncBinanceClientImpl.class)
|
||||
public interface AsyncBinanceClient {
|
||||
|
||||
/**
|
||||
* Get the ticker given the symbol.
|
||||
*/
|
||||
CompletionStage<Ticker> getTicker(String symbol);
|
||||
|
||||
/**
|
||||
* Get the depth given the symbol. Limit defaults to 100.
|
||||
*/
|
||||
CompletionStage<Depth> getDepth(String symbol);
|
||||
|
||||
/**
|
||||
* Get the depth given the symbol and limit.
|
||||
*/
|
||||
CompletionStage<Depth> getDepth(String symbol, int limit);
|
||||
|
||||
/**
|
||||
* Place a LIMIT order.
|
||||
*/
|
||||
CompletionStage<Order> placeLimitOrder(Keys keys, String symbol, OrderSide side,
|
||||
TimeInForce timeInForce, double quantity, double price);
|
||||
|
||||
/**
|
||||
* Place a MARKET order.
|
||||
*/
|
||||
CompletionStage<Order> placeMarketOrder(Keys keys, String symbol, OrderSide side,
|
||||
double quantity);
|
||||
|
||||
/**
|
||||
* Check the status of an order.
|
||||
*/
|
||||
CompletionStage<OrderStatus> checkOrderStatus(Keys keys, Order order);
|
||||
|
||||
/**
|
||||
* Cancel an order.
|
||||
*/
|
||||
CompletionStage<CancelOrder> cancelOrder(Keys keys, Order order);
|
||||
|
||||
/**
|
||||
* Get all open orders.
|
||||
*/
|
||||
CompletionStage<List<OrderStatus>> getOpenOrders(Keys keys, String symbol);
|
||||
|
||||
/**
|
||||
* Get account info.
|
||||
*/
|
||||
CompletionStage<Account> getAccount(Keys keys);
|
||||
|
||||
}
|
@ -1,223 +0,0 @@
|
||||
package com.github.johnsiu.binance.httpclients;
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.github.johnsiu.binance.exceptions.ClientErrorException;
|
||||
import com.github.johnsiu.binance.inject.BinanceClientModule;
|
||||
import com.github.johnsiu.binance.models.Account;
|
||||
import com.github.johnsiu.binance.models.CancelOrder;
|
||||
import com.github.johnsiu.binance.models.Depth;
|
||||
import com.github.johnsiu.binance.models.ErrorDetails;
|
||||
import com.github.johnsiu.binance.models.Keys;
|
||||
import com.github.johnsiu.binance.models.Order;
|
||||
import com.github.johnsiu.binance.models.Order.OrderSide;
|
||||
import com.github.johnsiu.binance.models.Order.OrderType;
|
||||
import com.github.johnsiu.binance.models.Order.TimeInForce;
|
||||
import com.github.johnsiu.binance.models.OrderStatus;
|
||||
import com.github.johnsiu.binance.models.Ticker;
|
||||
import io.netty.handler.codec.http.HttpMethod;
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CompletionException;
|
||||
import java.util.concurrent.CompletionStage;
|
||||
import java.util.function.Function;
|
||||
import javax.crypto.Mac;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import org.asynchttpclient.AsyncHttpClient;
|
||||
import org.asynchttpclient.BoundRequestBuilder;
|
||||
import org.asynchttpclient.Response;
|
||||
|
||||
/**
|
||||
* Concrete implementation of {@link AsyncBinanceClient}.
|
||||
*/
|
||||
public class AsyncBinanceClientImpl implements AsyncBinanceClient {
|
||||
|
||||
private static final String HMAC_SHA256 = "HmacSHA256";
|
||||
private static final String APIKEY_HEADER = "X-MBX-APIKEY";
|
||||
private static final String ORDER_ENDPOINT = "order";
|
||||
private static final String OPEN_ORDERS_ENDPOINT = "openOrders";
|
||||
private static final String ACCOUNT_ENDPOINT = "account";
|
||||
private final String API_URL = "https://www.binance.com/api/v1/";
|
||||
private final String API_V3_URL = "https://www.binance.com/api/v3/";
|
||||
private final AsyncHttpClient asyncHttpClient;
|
||||
private final ObjectMapper objectMapper;
|
||||
|
||||
@Inject
|
||||
public AsyncBinanceClientImpl(AsyncHttpClient asyncHttpClient,
|
||||
@Named(BinanceClientModule.BINANCE_CLIENT) ObjectMapper objectMapper) {
|
||||
this.asyncHttpClient = asyncHttpClient;
|
||||
this.objectMapper = objectMapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletionStage<Ticker> getTicker(String symbol) {
|
||||
|
||||
return handleResponse(
|
||||
asyncHttpClient.prepareGet(API_URL + "ticker/24hr?symbol=" + symbol).execute()
|
||||
.toCompletableFuture(), new TypeReference<Ticker>() {
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletionStage<Depth> getDepth(String symbol) {
|
||||
return getDepth(symbol, 100);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletionStage<Depth> getDepth(String symbol, int limit) {
|
||||
|
||||
return handleResponse(asyncHttpClient.prepareGet(API_URL + "depth?symbol=" + symbol).execute()
|
||||
.toCompletableFuture(), new TypeReference<Depth>() {
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletionStage<Order> placeLimitOrder(Keys keys, String symbol, OrderSide side,
|
||||
TimeInForce timeInForce, double quantity, double price) {
|
||||
|
||||
String queryStr = String.format(
|
||||
"symbol=%s&side=%s&type=%s&timeInForce=%s&quantity=%f&price=%f×tamp=%d",
|
||||
symbol, side.name(), OrderType.LIMIT, timeInForce.name(), quantity, price,
|
||||
System.currentTimeMillis());
|
||||
|
||||
return makeSignedRequest(keys, HttpMethod.POST, ORDER_ENDPOINT, queryStr,
|
||||
new TypeReference<Order>() {
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletionStage<Order> placeMarketOrder(Keys keys, String symbol, OrderSide side,
|
||||
double quantity) {
|
||||
|
||||
String queryStr = String.format(
|
||||
"symbol=%s&side=%s&type=%s&quantity=%f×tamp=%d",
|
||||
symbol, side.name(), OrderType.MARKET, quantity,
|
||||
System.currentTimeMillis());
|
||||
|
||||
return makeSignedRequest(keys, HttpMethod.POST, ORDER_ENDPOINT, queryStr,
|
||||
new TypeReference<Order>() {
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletionStage<OrderStatus> checkOrderStatus(Keys keys, Order order) {
|
||||
|
||||
String queryStr = String.format(
|
||||
"symbol=%s&orderId=%d&origClientOrderId=%s×tamp=%d",
|
||||
order.getSymbol(), order.getOrderId(), order.getClientOrderId(),
|
||||
System.currentTimeMillis());
|
||||
|
||||
return makeSignedRequest(keys, HttpMethod.GET, ORDER_ENDPOINT, queryStr,
|
||||
new TypeReference<OrderStatus>() {
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletionStage<CancelOrder> cancelOrder(Keys keys, Order order) {
|
||||
|
||||
String queryStr = String.format(
|
||||
"symbol=%s&orderId=%d&origClientOrderId=%s×tamp=%d",
|
||||
order.getSymbol(), order.getOrderId(), order.getClientOrderId(),
|
||||
System.currentTimeMillis());
|
||||
return makeSignedRequest(keys, HttpMethod.DELETE, ORDER_ENDPOINT, queryStr,
|
||||
new TypeReference<CancelOrder>() {
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletionStage<List<OrderStatus>> getOpenOrders(Keys keys, String symbol) {
|
||||
|
||||
String queryStr = String.format(
|
||||
"symbol=%s×tamp=%d", symbol, System.currentTimeMillis());
|
||||
|
||||
return makeSignedRequest(keys, HttpMethod.GET, OPEN_ORDERS_ENDPOINT, queryStr,
|
||||
new TypeReference<List<OrderStatus>>() {
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletionStage<Account> getAccount(Keys keys) {
|
||||
|
||||
String queryStr = String.format(
|
||||
"timestamp=%d", System.currentTimeMillis());
|
||||
|
||||
return makeSignedRequest(keys, HttpMethod.GET, ACCOUNT_ENDPOINT, queryStr,
|
||||
new TypeReference<Account>() {
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private <T> CompletionStage<T> makeSignedRequest(Keys keys, HttpMethod method, String endpoint,
|
||||
String queryStr, TypeReference<T> typeReference) {
|
||||
|
||||
return CompletableFuture.supplyAsync(() -> {
|
||||
try {
|
||||
String signature = signQueryString(keys, queryStr);
|
||||
String url = API_V3_URL + endpoint + "?" + queryStr + "&signature=" + signature;
|
||||
BoundRequestBuilder boundRequestBuilder;
|
||||
if (method == HttpMethod.GET) {
|
||||
boundRequestBuilder = asyncHttpClient.prepareGet(url);
|
||||
} else if (method == HttpMethod.POST) {
|
||||
boundRequestBuilder = asyncHttpClient.preparePost(url);
|
||||
} else if (method == HttpMethod.DELETE) {
|
||||
boundRequestBuilder = asyncHttpClient.prepareDelete(url);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unsupported method: " + method);
|
||||
}
|
||||
return handleResponse(boundRequestBuilder
|
||||
.addHeader(
|
||||
APIKEY_HEADER, keys.getApiKey())
|
||||
.execute().toCompletableFuture(), typeReference);
|
||||
} catch (UnsupportedEncodingException | NoSuchAlgorithmException | InvalidKeyException e) {
|
||||
throw new CompletionException(e);
|
||||
}
|
||||
}).thenCompose(Function.identity());
|
||||
}
|
||||
|
||||
private String signQueryString(Keys keys, String queryString)
|
||||
throws InvalidKeyException, NoSuchAlgorithmException, UnsupportedEncodingException {
|
||||
|
||||
byte[] byteKey = keys.getSecretKey().getBytes("UTF-8");
|
||||
Mac sha256HMAC = Mac.getInstance(HMAC_SHA256);
|
||||
sha256HMAC.init(new SecretKeySpec(byteKey, HMAC_SHA256));
|
||||
return bytesToHex(sha256HMAC.doFinal(queryString.getBytes("UTF-8")));
|
||||
}
|
||||
|
||||
private <T> CompletionStage<T> handleResponse(CompletableFuture<Response> responseFuture,
|
||||
TypeReference<T> typeReference) {
|
||||
|
||||
return responseFuture.thenApply(response -> {
|
||||
try {
|
||||
if (response.getStatusCode() >= 400) {
|
||||
throw new ClientErrorException(response.getStatusCode(),
|
||||
objectMapper.readValue(response.getResponseBody(), ErrorDetails.class));
|
||||
}
|
||||
return objectMapper.readValue(response.getResponseBody(), typeReference);
|
||||
} catch (IOException e) {
|
||||
throw new CompletionException(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
final private static char[] hexArray = "0123456789ABCDEF"
|
||||
.toCharArray();
|
||||
|
||||
private String bytesToHex(byte[] bytes) {
|
||||
|
||||
char[] hexChars = new char[bytes.length * 2];
|
||||
int v;
|
||||
for (int j = 0; j < bytes.length; j++) {
|
||||
v = bytes[j] & 0xFF;
|
||||
hexChars[j * 2] = hexArray[v >>> 4];
|
||||
hexChars[j * 2 + 1] = hexArray[v & 0x0F];
|
||||
}
|
||||
return new String(hexChars);
|
||||
}
|
||||
}
|
@ -1,68 +0,0 @@
|
||||
package com.github.johnsiu.binance.httpclients;
|
||||
|
||||
import com.github.johnsiu.binance.models.Account;
|
||||
import com.github.johnsiu.binance.models.CancelOrder;
|
||||
import com.github.johnsiu.binance.models.Depth;
|
||||
import com.github.johnsiu.binance.models.Keys;
|
||||
import com.github.johnsiu.binance.models.Order;
|
||||
import com.github.johnsiu.binance.models.Order.OrderSide;
|
||||
import com.github.johnsiu.binance.models.Order.TimeInForce;
|
||||
import com.github.johnsiu.binance.models.OrderStatus;
|
||||
import com.github.johnsiu.binance.models.Ticker;
|
||||
import com.google.inject.ImplementedBy;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Client for accessing Binance API.
|
||||
*/
|
||||
@ImplementedBy(BinanceClientImpl.class)
|
||||
public interface BinanceClient {
|
||||
|
||||
/**
|
||||
* Get the ticker given the symbol.
|
||||
*/
|
||||
Ticker getTicker(String symbol);
|
||||
|
||||
/**
|
||||
* Get the depth given the symbol. Limit defaults to 100.
|
||||
*/
|
||||
Depth getDepth(String symbol);
|
||||
|
||||
/**
|
||||
* Get the depth given the symbol and limit.
|
||||
*/
|
||||
Depth getDepth(String symbol, int limit);
|
||||
|
||||
/**
|
||||
* Place a LIMIT order.
|
||||
*/
|
||||
Order placeLimitOrder(Keys keys, String symbol, OrderSide side,
|
||||
TimeInForce timeInForce, double quantity, double price);
|
||||
|
||||
/**
|
||||
* Place a MARKET order.
|
||||
*/
|
||||
Order placeMarketOrder(Keys keys, String symbol, OrderSide side,
|
||||
double quantity);
|
||||
|
||||
/**
|
||||
* Check the status of an order.
|
||||
*/
|
||||
OrderStatus checkOrderStatus(Keys keys, Order order);
|
||||
|
||||
/**
|
||||
* Cancel an order.
|
||||
*/
|
||||
CancelOrder cancelOrder(Keys keys, Order order);
|
||||
|
||||
/**
|
||||
* Get all open orders.
|
||||
*/
|
||||
List<OrderStatus> getOpenOrders(Keys keys, String symbol);
|
||||
|
||||
/**
|
||||
* Get account info.
|
||||
*/
|
||||
Account getAccount(Keys keys);
|
||||
|
||||
}
|
@ -1,90 +0,0 @@
|
||||
package com.github.johnsiu.binance.httpclients;
|
||||
|
||||
import com.github.johnsiu.binance.models.Account;
|
||||
import com.github.johnsiu.binance.models.CancelOrder;
|
||||
import com.github.johnsiu.binance.models.Depth;
|
||||
import com.github.johnsiu.binance.models.Keys;
|
||||
import com.github.johnsiu.binance.models.Order;
|
||||
import com.github.johnsiu.binance.models.Order.OrderSide;
|
||||
import com.github.johnsiu.binance.models.Order.TimeInForce;
|
||||
import com.github.johnsiu.binance.models.OrderStatus;
|
||||
import com.github.johnsiu.binance.models.Ticker;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletionException;
|
||||
import java.util.concurrent.CompletionStage;
|
||||
import javax.inject.Inject;
|
||||
|
||||
/**
|
||||
* Concrete implementation of {@link BinanceClient}.
|
||||
*/
|
||||
public class BinanceClientImpl implements BinanceClient {
|
||||
|
||||
private final AsyncBinanceClient asyncBinanceClient;
|
||||
|
||||
@Inject
|
||||
public BinanceClientImpl(AsyncBinanceClient asyncBinanceClient) {
|
||||
this.asyncBinanceClient = asyncBinanceClient;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Ticker getTicker(String symbol) {
|
||||
return joinAsync(asyncBinanceClient.getTicker(symbol));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Depth getDepth(String symbol) {
|
||||
return joinAsync(asyncBinanceClient.getDepth(symbol));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Depth getDepth(String symbol, int limit) {
|
||||
return joinAsync(asyncBinanceClient.getDepth(symbol, limit));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Order placeLimitOrder(Keys keys, String symbol, OrderSide side,
|
||||
TimeInForce timeInForce, double quantity, double price) {
|
||||
return joinAsync(
|
||||
asyncBinanceClient.placeLimitOrder(keys, symbol, side, timeInForce, quantity, price)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Order placeMarketOrder(Keys keys, String symbol, OrderSide side,
|
||||
double quantity) {
|
||||
return joinAsync(
|
||||
asyncBinanceClient.placeMarketOrder(keys, symbol, side, quantity)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public OrderStatus checkOrderStatus(Keys keys, Order order) {
|
||||
return joinAsync(asyncBinanceClient.checkOrderStatus(keys, order));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CancelOrder cancelOrder(Keys keys, Order order) {
|
||||
return joinAsync(asyncBinanceClient.cancelOrder(keys, order));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<OrderStatus> getOpenOrders(Keys keys, String symbol) {
|
||||
return joinAsync(asyncBinanceClient.getOpenOrders(keys, symbol));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Account getAccount(Keys keys) {
|
||||
return joinAsync(asyncBinanceClient.getAccount(keys));
|
||||
}
|
||||
|
||||
private <T> T joinAsync(CompletionStage<T> completionStage) {
|
||||
try {
|
||||
return completionStage.toCompletableFuture().join();
|
||||
} catch (CompletionException e) {
|
||||
if (e.getCause() instanceof RuntimeException) {
|
||||
throw (RuntimeException) e.getCause();
|
||||
}
|
||||
throw new RuntimeException(e.getCause());
|
||||
}
|
||||
}
|
||||
}
|
@ -1,24 +0,0 @@
|
||||
package com.github.johnsiu.binance.inject;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.google.inject.AbstractModule;
|
||||
import com.google.inject.name.Names;
|
||||
import org.asynchttpclient.AsyncHttpClient;
|
||||
import org.asynchttpclient.DefaultAsyncHttpClient;
|
||||
|
||||
/**
|
||||
* Guice module for dependency injection.
|
||||
*/
|
||||
public class BinanceClientModule extends AbstractModule {
|
||||
|
||||
public static final String BINANCE_CLIENT = "BinanceClient";
|
||||
|
||||
@Override
|
||||
protected void configure() {
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
bind(ObjectMapper.class)
|
||||
.annotatedWith(Names.named(BINANCE_CLIENT))
|
||||
.toInstance(objectMapper);
|
||||
bind(AsyncHttpClient.class).to(DefaultAsyncHttpClient.class);
|
||||
}
|
||||
}
|
@ -1,98 +0,0 @@
|
||||
package com.github.johnsiu.binance.models;
|
||||
|
||||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
||||
import java.util.Map;
|
||||
import com.github.johnsiu.binance.deser.BalanceMapDeserializer;
|
||||
|
||||
/**
|
||||
* Represents an account info.
|
||||
*/
|
||||
public class Account {
|
||||
|
||||
private int makerCommission;
|
||||
private int takerCommission;
|
||||
private int buyerCommission;
|
||||
private int sellerCommission;
|
||||
private boolean canTrade;
|
||||
private boolean canWithdraw;
|
||||
private boolean canDeposit;
|
||||
// asset to Balance
|
||||
private Map<String, Balance> balances;
|
||||
|
||||
public int getMakerCommission() {
|
||||
return makerCommission;
|
||||
}
|
||||
|
||||
public int getTakerCommission() {
|
||||
return takerCommission;
|
||||
}
|
||||
|
||||
public int getBuyerCommission() {
|
||||
return buyerCommission;
|
||||
}
|
||||
|
||||
public int getSellerCommission() {
|
||||
return sellerCommission;
|
||||
}
|
||||
|
||||
public boolean isCanTrade() {
|
||||
return canTrade;
|
||||
}
|
||||
|
||||
public boolean isCanWithdraw() {
|
||||
return canWithdraw;
|
||||
}
|
||||
|
||||
public boolean isCanDeposit() {
|
||||
return canDeposit;
|
||||
}
|
||||
|
||||
@JsonDeserialize(using = BalanceMapDeserializer.class)
|
||||
public Map<String, Balance> getBalances() {
|
||||
return balances;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Account{" +
|
||||
"makerCommission=" + makerCommission +
|
||||
", takerCommission=" + takerCommission +
|
||||
", buyerCommission=" + buyerCommission +
|
||||
", sellerCommission=" + sellerCommission +
|
||||
", canTrade=" + canTrade +
|
||||
", canWithdraw=" + canWithdraw +
|
||||
", canDeposit=" + canDeposit +
|
||||
", balances=" + balances +
|
||||
'}';
|
||||
}
|
||||
|
||||
public static class Balance {
|
||||
|
||||
private String asset;
|
||||
private double free;
|
||||
private double locked;
|
||||
|
||||
public String getAsset() {
|
||||
return asset;
|
||||
}
|
||||
|
||||
public double getFree() {
|
||||
return free;
|
||||
}
|
||||
|
||||
public double getLocked() {
|
||||
return locked;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Balance{" +
|
||||
"asset='" + asset + '\'' +
|
||||
", free=" + free +
|
||||
", locked=" + locked +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,38 +0,0 @@
|
||||
package com.github.johnsiu.binance.models;
|
||||
|
||||
/**
|
||||
* Represents a cancel order.
|
||||
*/
|
||||
public class CancelOrder {
|
||||
|
||||
private String symbol;
|
||||
private long orderId;
|
||||
private String origClientOrderId;
|
||||
private String clientOrderId;
|
||||
|
||||
public String getSymbol() {
|
||||
return symbol;
|
||||
}
|
||||
|
||||
public long getOrderId() {
|
||||
return orderId;
|
||||
}
|
||||
|
||||
public String getOrigClientOrderId() {
|
||||
return origClientOrderId;
|
||||
}
|
||||
|
||||
public String getClientOrderId() {
|
||||
return clientOrderId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "CancelOrder{" +
|
||||
"symbol='" + symbol + '\'' +
|
||||
", orderId=" + orderId +
|
||||
", origClientOrderId='" + origClientOrderId + '\'' +
|
||||
", clientOrderId='" + clientOrderId + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
@ -1,61 +0,0 @@
|
||||
package com.github.johnsiu.binance.models;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableList.Builder;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* Represents depth of a symbol.
|
||||
*/
|
||||
public class Depth {
|
||||
|
||||
private long lastUpdateId;
|
||||
private List<PriceQuantity> bids;
|
||||
private List<PriceQuantity> asks;
|
||||
|
||||
@JsonCreator
|
||||
public Depth(@JsonProperty("lastUpdateId") long lastUpdateId, @JsonProperty("bids") List<?> bids,
|
||||
@JsonProperty("asks") List<?> asks) {
|
||||
this.lastUpdateId = lastUpdateId;
|
||||
|
||||
Function<List<?>, List<PriceQuantity>> buildOrdersFunc = (orders) -> {
|
||||
Builder<PriceQuantity> ordersBuilder = ImmutableList.<PriceQuantity>builder();
|
||||
if (orders != null && orders.size() >= 2) {
|
||||
orders.forEach(value -> {
|
||||
Iterator iterator = Collection.class.cast(value).iterator();
|
||||
ordersBuilder.add(new PriceQuantity(Double.valueOf((String) iterator.next()),
|
||||
Double.valueOf((String) iterator.next())));
|
||||
});
|
||||
}
|
||||
return ordersBuilder.build();
|
||||
};
|
||||
this.bids = buildOrdersFunc.apply(bids);
|
||||
this.asks = buildOrdersFunc.apply(asks);
|
||||
}
|
||||
|
||||
public long getLastUpdateId() {
|
||||
return lastUpdateId;
|
||||
}
|
||||
|
||||
public List<PriceQuantity> getBids() {
|
||||
return bids;
|
||||
}
|
||||
|
||||
public List<PriceQuantity> getAsks() {
|
||||
return asks;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Depth{" +
|
||||
"lastUpdateId=" + lastUpdateId +
|
||||
", bids=" + bids +
|
||||
", asks=" + asks +
|
||||
'}';
|
||||
}
|
||||
}
|
@ -1,26 +0,0 @@
|
||||
package com.github.johnsiu.binance.models;
|
||||
|
||||
/**
|
||||
* Represents an error from Binance API.
|
||||
*/
|
||||
public class ErrorDetails {
|
||||
|
||||
private long code;
|
||||
private String msg;
|
||||
|
||||
public long getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public String getMsg() {
|
||||
return msg;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ErrorDetails{" +
|
||||
"code=" + code +
|
||||
", msg='" + msg + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
package com.github.johnsiu.binance.models;
|
||||
|
||||
/**
|
||||
* Represents API key and secret key for accessing SIGNED endpoints.
|
||||
*/
|
||||
public class Keys {
|
||||
|
||||
private String apiKey;
|
||||
private String secretKey;
|
||||
|
||||
public Keys(String apiKey, String secretKey) {
|
||||
this.apiKey = apiKey;
|
||||
this.secretKey = secretKey;
|
||||
}
|
||||
|
||||
public String getApiKey() {
|
||||
return apiKey;
|
||||
}
|
||||
|
||||
public String getSecretKey() {
|
||||
return secretKey;
|
||||
}
|
||||
}
|
@ -1,55 +0,0 @@
|
||||
package com.github.johnsiu.binance.models;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* Represents an Order. Can be cancelled.
|
||||
*/
|
||||
public class Order {
|
||||
|
||||
private String symbol;
|
||||
private long orderId;
|
||||
private String clientOrderId;
|
||||
private Date transactTime;
|
||||
|
||||
public String getSymbol() {
|
||||
return symbol;
|
||||
}
|
||||
|
||||
public long getOrderId() {
|
||||
return orderId;
|
||||
}
|
||||
|
||||
public String getClientOrderId() {
|
||||
return clientOrderId;
|
||||
}
|
||||
|
||||
public Date getTransactTime() {
|
||||
return transactTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Order{" +
|
||||
"symbol='" + symbol + '\'' +
|
||||
", orderId=" + orderId +
|
||||
", clientOrderId='" + clientOrderId + '\'' +
|
||||
", transactTime=" + transactTime +
|
||||
'}';
|
||||
}
|
||||
|
||||
public enum OrderSide {
|
||||
BUY, SELL
|
||||
}
|
||||
|
||||
public enum OrderType {
|
||||
LIMIT, MARKET
|
||||
}
|
||||
|
||||
public enum TimeInForce {
|
||||
// Good Till Cancel
|
||||
GTC,
|
||||
// Immediate or Cancel
|
||||
IOC
|
||||
}
|
||||
}
|
@ -1,86 +0,0 @@
|
||||
package com.github.johnsiu.binance.models;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* Represents an order status. Can be cancelled.
|
||||
*/
|
||||
public class OrderStatus extends Order {
|
||||
|
||||
private String price;
|
||||
private String origQty;
|
||||
private String executedQty;
|
||||
private Status status;
|
||||
private TimeInForce timeInForce;
|
||||
private OrderType type;
|
||||
private OrderSide side;
|
||||
private String stopPrice;
|
||||
private String icebergQty;
|
||||
private Date time;
|
||||
|
||||
public String getPrice() {
|
||||
return price;
|
||||
}
|
||||
|
||||
public String getOrigQty() {
|
||||
return origQty;
|
||||
}
|
||||
|
||||
public String getExecutedQty() {
|
||||
return executedQty;
|
||||
}
|
||||
|
||||
public Status getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public TimeInForce getTimeInForce() {
|
||||
return timeInForce;
|
||||
}
|
||||
|
||||
public OrderType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public OrderSide getSide() {
|
||||
return side;
|
||||
}
|
||||
|
||||
public String getStopPrice() {
|
||||
return stopPrice;
|
||||
}
|
||||
|
||||
public String getIcebergQty() {
|
||||
return icebergQty;
|
||||
}
|
||||
|
||||
public Date getTime() {
|
||||
return time;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "OrderStatus{" +
|
||||
"price='" + price + '\'' +
|
||||
", origQty='" + origQty + '\'' +
|
||||
", executedQty='" + executedQty + '\'' +
|
||||
", status=" + status +
|
||||
", timeInForce=" + timeInForce +
|
||||
", type=" + type +
|
||||
", side=" + side +
|
||||
", stopPrice='" + stopPrice + '\'' +
|
||||
", icebergQty='" + icebergQty + '\'' +
|
||||
", time=" + time +
|
||||
"} " + super.toString();
|
||||
}
|
||||
|
||||
public enum Status {
|
||||
NEW,
|
||||
PARTIALLY_FILLED,
|
||||
FILLED,
|
||||
CANCELED,
|
||||
PENDING_CANCEL,
|
||||
REJECTED,
|
||||
EXPIRED
|
||||
}
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
package com.github.johnsiu.binance.models;
|
||||
|
||||
/**
|
||||
* Represents price and quantity of a bid or an ask.
|
||||
*/
|
||||
public class PriceQuantity {
|
||||
|
||||
private double price;
|
||||
private double quantity;
|
||||
|
||||
public PriceQuantity(double price, double quantity) {
|
||||
this.price = price;
|
||||
this.quantity = quantity;
|
||||
}
|
||||
|
||||
public double getPrice() {
|
||||
return price;
|
||||
}
|
||||
|
||||
public double getQuantity() {
|
||||
return quantity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PriceQuantity{" +
|
||||
"price=" + price +
|
||||
", quantity=" + quantity +
|
||||
'}';
|
||||
}
|
||||
}
|
@ -1,137 +0,0 @@
|
||||
package com.github.johnsiu.binance.models;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* Represents a ticker of a symbol.
|
||||
*/
|
||||
public class Ticker {
|
||||
|
||||
private double priceChange;
|
||||
private double priceChangePercent;
|
||||
private double weightedAvgPrice;
|
||||
private double prevClosePrice;
|
||||
private double lastPrice;
|
||||
private double lastQty;
|
||||
private double bidPrice;
|
||||
private double bidQty;
|
||||
private double askPrice;
|
||||
private double askQty;
|
||||
private double openPrice;
|
||||
private double highPrice;
|
||||
private double lowPrice;
|
||||
private double volume;
|
||||
private double quoteVolume;
|
||||
private Date openTime;
|
||||
private Date closeTime;
|
||||
private long firstId;
|
||||
private long lastId;
|
||||
private long count;
|
||||
|
||||
public double getPriceChange() {
|
||||
return priceChange;
|
||||
}
|
||||
|
||||
public double getPriceChangePercent() {
|
||||
return priceChangePercent;
|
||||
}
|
||||
|
||||
public double getWeightedAvgPrice() {
|
||||
return weightedAvgPrice;
|
||||
}
|
||||
|
||||
public double getPrevClosePrice() {
|
||||
return prevClosePrice;
|
||||
}
|
||||
|
||||
public double getLastPrice() {
|
||||
return lastPrice;
|
||||
}
|
||||
|
||||
public double getLastQty() {
|
||||
return lastQty;
|
||||
}
|
||||
|
||||
public double getBidPrice() {
|
||||
return bidPrice;
|
||||
}
|
||||
|
||||
public double getBidQty() {
|
||||
return bidQty;
|
||||
}
|
||||
|
||||
public double getAskPrice() {
|
||||
return askPrice;
|
||||
}
|
||||
|
||||
public double getAskQty() {
|
||||
return askQty;
|
||||
}
|
||||
|
||||
public double getOpenPrice() {
|
||||
return openPrice;
|
||||
}
|
||||
|
||||
public double getHighPrice() {
|
||||
return highPrice;
|
||||
}
|
||||
|
||||
public double getLowPrice() {
|
||||
return lowPrice;
|
||||
}
|
||||
|
||||
public double getVolume() {
|
||||
return volume;
|
||||
}
|
||||
|
||||
public double getQuoteVolume() {
|
||||
return quoteVolume;
|
||||
}
|
||||
|
||||
public Date getOpenTime() {
|
||||
return openTime;
|
||||
}
|
||||
|
||||
public Date getCloseTime() {
|
||||
return closeTime;
|
||||
}
|
||||
|
||||
public long getFirstId() {
|
||||
return firstId;
|
||||
}
|
||||
|
||||
public long getLastId() {
|
||||
return lastId;
|
||||
}
|
||||
|
||||
public long getCount() {
|
||||
return count;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Ticker{" +
|
||||
"priceChange=" + priceChange +
|
||||
", priceChangePercent=" + priceChangePercent +
|
||||
", weightedAvgPrice=" + weightedAvgPrice +
|
||||
", prevClosePrice=" + prevClosePrice +
|
||||
", lastPrice=" + lastPrice +
|
||||
", lastQty=" + lastQty +
|
||||
", bidPrice=" + bidPrice +
|
||||
", bidQty=" + bidQty +
|
||||
", askPrice=" + askPrice +
|
||||
", askQty=" + askQty +
|
||||
", openPrice=" + openPrice +
|
||||
", highPrice=" + highPrice +
|
||||
", lowPrice=" + lowPrice +
|
||||
", volume=" + volume +
|
||||
", quoteVolume=" + quoteVolume +
|
||||
", openTime=" + openTime +
|
||||
", closeTime=" + closeTime +
|
||||
", firstId=" + firstId +
|
||||
", lastId=" + lastId +
|
||||
", count=" + count +
|
||||
'}';
|
||||
}
|
||||
|
||||
}
|
@ -1,87 +0,0 @@
|
||||
package com.github.johnsiu.binance.httpclients;
|
||||
|
||||
import com.github.johnsiu.binance.exceptions.ClientErrorException;
|
||||
import com.github.johnsiu.binance.inject.BinanceClientModule;
|
||||
import com.github.johnsiu.binance.models.Account;
|
||||
import com.github.johnsiu.binance.models.Depth;
|
||||
import com.github.johnsiu.binance.models.Keys;
|
||||
import com.github.johnsiu.binance.models.Order;
|
||||
import com.github.johnsiu.binance.models.Order.OrderSide;
|
||||
import com.github.johnsiu.binance.models.Order.TimeInForce;
|
||||
import com.github.johnsiu.binance.models.OrderStatus;
|
||||
import com.google.inject.Guice;
|
||||
import com.google.inject.Injector;
|
||||
import java.util.List;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Test case for {@link BinanceClientImpl}
|
||||
*/
|
||||
public class BinanceClientImplTest {
|
||||
|
||||
@Test
|
||||
public void testGetTicker() {
|
||||
Injector injector = Guice.createInjector(new BinanceClientModule());
|
||||
BinanceClient client = injector.getInstance(BinanceClient.class);
|
||||
|
||||
Assert.assertNotNull(client.getTicker("ETHBTC"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetDepth() {
|
||||
Injector injector = Guice.createInjector(new BinanceClientModule());
|
||||
BinanceClient client = injector.getInstance(BinanceClient.class);
|
||||
|
||||
Assert.assertNotNull(client.getDepth("ETHBTC"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetDepthError() {
|
||||
Injector injector = Guice.createInjector(new BinanceClientModule());
|
||||
BinanceClient client = injector.getInstance(BinanceClient.class);
|
||||
|
||||
try {
|
||||
Depth depth = client.getDepth("ETHBT");
|
||||
Assert.fail();
|
||||
} catch (Exception e) {
|
||||
ClientErrorException cast = (ClientErrorException) e;
|
||||
Assert.assertEquals("Invalid symbol.", cast.getErrorDetails().getMsg());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOrder() {
|
||||
Injector injector = Guice.createInjector(new BinanceClientModule());
|
||||
BinanceClient client = injector.getInstance(BinanceClient.class);
|
||||
|
||||
Keys keys = new Keys(System.getProperty("apiKey"),
|
||||
System.getProperty("secretKey"));
|
||||
String symbol = "MCOETH";
|
||||
Order order = client
|
||||
.placeLimitOrder(keys, symbol, OrderSide.BUY, TimeInForce.GTC, 1, 0.020041);
|
||||
Assert.assertNotNull(order);
|
||||
|
||||
OrderStatus orderStatus = client.checkOrderStatus(keys, order);
|
||||
Assert.assertNotNull(orderStatus);
|
||||
|
||||
List<OrderStatus> openOrders = client.getOpenOrders(keys, symbol);
|
||||
Assert.assertFalse(openOrders.isEmpty());
|
||||
|
||||
openOrders.forEach(openOrder -> client.cancelOrder(keys, openOrder));
|
||||
|
||||
openOrders = client.getOpenOrders(keys, symbol);
|
||||
Assert.assertTrue(openOrders.isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAccount() {
|
||||
Injector injector = Guice.createInjector(new BinanceClientModule());
|
||||
BinanceClient client = injector.getInstance(BinanceClient.class);
|
||||
|
||||
Keys keys = new Keys(System.getProperty("apiKey"),
|
||||
System.getProperty("secretKey"));
|
||||
Account account = client.getAccount(keys);
|
||||
Assert.assertNotNull(account);
|
||||
}
|
||||
}
|
BIN
libs/binance-api.jar
Normal file
BIN
libs/binance-api.jar
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user