Starting impl of Symbol conf page

This commit is contained in:
Ziver Koc 2021-05-24 00:40:07 +02:00
parent 0ae1c08505
commit 245a599b52
9 changed files with 185 additions and 92 deletions

View file

@ -4,6 +4,7 @@ import se.koc.trader.api.ExchangeConfig;
import se.koc.trader.endpoint.AlertEndpoint;
import se.koc.trader.api.TraderApiEndpoint;
import se.koc.trader.daemon.TraderMarketUpdateManager;
import se.koc.trader.endpoint.ExchangeEndpoint;
import se.koc.trader.struct.Exchange;
import se.koc.trader.struct.PluginConfig;
import se.koc.trader.api.TraderPage;
@ -13,6 +14,7 @@ import zutil.log.LogUtil;
import zutil.net.http.HttpServer;
import zutil.net.http.page.HttpFilePage;
import zutil.net.http.page.HttpRedirectPage;
import zutil.net.ws.rest.RESTHttpPage;
import zutil.plugin.PluginData;
import zutil.plugin.PluginManager;
@ -96,6 +98,7 @@ public class TraderServer {
registerPage(it.next());
for (Iterator<TraderPage> it = pluginManager.getSingletonIterator(TraderPage.class); it.hasNext(); )
registerPage(it.next());
http.setPage(ExchangeEndpoint.API_PATH, new RESTHttpPage(new ExchangeEndpoint()));
http.start();
}

View file

@ -0,0 +1,30 @@
package se.koc.trader.endpoint;
import se.koc.trader.TraderContext;
import se.koc.trader.struct.Exchange;
import se.koc.trader.struct.Symbol;
import zutil.db.DBConnection;
import zutil.net.ws.WSInterface;
import zutil.parser.DataNode;
import java.sql.SQLException;
public class ExchangeEndpoint implements WSInterface {
public static final String API_PATH = "/api/exchange";
@WSPath(API_PATH + "/symbols")
public DataNode getAllSymbols(int exchangeId) throws SQLException {
DBConnection db = TraderContext.getDB();
DataNode root = new DataNode(DataNode.DataType.Map);
Exchange exchange = Exchange.getExchange(db, exchangeId);
DataNode symbols = root.set("symbols", DataNode.DataType.List);
for (Symbol symbol : exchange.getObject().getExchangeMarket().getSymbols()) {
symbols.add(symbol.getName());
}
return root;
}
}

View file

@ -3,9 +3,24 @@ package se.koc.trader.exchange.binance;
import se.koc.trader.api.ExchangeConfig;
import se.koc.trader.api.ExchangeMarket;
import se.koc.trader.api.ExchangeWallet;
import zutil.ui.conf.Configurator;
public class BinanceExchange extends ExchangeConfig {
private BinanceMarket market;
@Configurator.Configurable("Binance API Key")
private String apiKey;
transient private BinanceMarket market;
public String getApiKey() {
return apiKey;
}
public void setApiKey(String apiKey) {
this.apiKey = apiKey;
}
@Override
public ExchangeMarket getExchangeMarket() {

View file

@ -2,6 +2,7 @@ package se.koc.trader.page;
import se.koc.trader.TraderContext;
import se.koc.trader.api.TraderPage;
import se.koc.trader.struct.Exchange;
import se.koc.trader.struct.Symbol;
import zutil.ObjectUtil;
import zutil.db.DBConnection;
@ -80,6 +81,7 @@ public class SymbolConfigPage extends TraderPage {
// Output
Templator tmpl = new Templator(FileUtil.find(TEMPLATE));
tmpl.set("exchanges", Exchange.getExchanges(db));
tmpl.set("symbols", Symbol.getSymbols(db));
return tmpl;

View file

@ -1,9 +1,11 @@
package se.koc.trader.struct;
import se.koc.trader.api.ExchangeConfig;
import se.koc.trader.util.ConfigExchangeValueProvider;
import zutil.db.DBConnection;
import zutil.db.bean.DBBean;
import zutil.db.bean.DBBeanObjectDSO;
import zutil.ui.Configurator;
import java.sql.SQLException;
import java.util.List;
@ -19,6 +21,7 @@ public class Symbol extends DBBean {
private double price;
private long priceTimestamp;
@Configurator.Configurable(value = "Exchange", description = "The exchange instance where symbol exists.", valueProvider = ConfigExchangeValueProvider.class)
private ExchangeConfig exchangeConfig;

View file

@ -0,0 +1,37 @@
package se.koc.trader.util;
import se.koc.trader.TraderContext;
import se.koc.trader.struct.Exchange;
import zutil.db.DBConnection;
import zutil.ui.Configurator;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
/**
* A value provider that will give all Enum values
*/
public class ConfigExchangeValueProvider implements Configurator.ConfigValueProvider<Exchange> {
Map<String, Exchange> map = new HashMap<>();
@Override
public String[] getPossibleValues() {
DBConnection db = TraderContext.getDB();
try {
for (Exchange exchange : Exchange.getExchanges(db)) {
map.put(exchange.getName() + " (Id: " + exchange.getId() + ")", exchange);
}
} catch (SQLException e) {
e.printStackTrace();
}
return map.keySet().toArray(new String[0]);
}
@Override
public Exchange getValueObject(String value) {
return map.get(value);
}
}

View file

@ -1,15 +1,6 @@
<div class="col-md-12 d-flex">
<div class="card flex-fill w-100">
<div class="card-header">
<div class="card-actions float-end">
<div class="btn-group float-end" role="group">
<button type="button" class="btn btn-success"
data-bs-toggle="modal" data-bs-target="#exchangeModal" data-action="create_exchange">
<i class="bi bi-plus"></i>
</button>
</div>
</div>
<h5 class="card-title mb-0">Exchange Instances</h5>
</div>
@ -21,7 +12,16 @@
<th>Name</th>
<th>Type</th>
<th>Configuration</th>
<th class="text-end">Actions</th>
<th class="text-end">
<div class="card-actions float-end">
<div class="btn-group float-end" role="group">
<button type="button" class="btn btn-success btn-sm"
data-bs-toggle="modal" data-bs-target="#exchangeModal" data-action="create_exchange">
<i class="bi bi-plus"></i>
</button>
</div>
</div>
</th>
</tr>
</thead>
<tbody>
@ -83,12 +83,12 @@
<input type="hidden" id="id" name="id">
<div>
<label for="input-name" class="form-label">Name:</label>
<input id="input-name" type="text" class="form-control" name="name">
<input id="input-name" type="text" name="name" class="form-control">
</div>
<div>
<label for="input-type" class="form-label">Type:</label>
<select id="input-type" class="form-control" name="type">
<select id="input-type" name="type" class="form-control" >
{{#exchangeConfigClasses}}
<option>{{.getName()}}</option>
{{/exchangeConfigClasses}}
@ -116,13 +116,13 @@
<label for="input-{{.getName()}}" class="form-label">{{.getNiceName()}}:</label>
{{#.isTypeString()}}<input id="input-{{.getName()}}" type="text" class="form-control" name="{{.getName()}}">{{/#.isTypeString()}}
{{#.isTypeInt()}}<input id="input-{{.getName()}}" type="number" class="form-control" name="{{.getName()}}">{{/#.isTypeInt()}}
{{#.isTypeNumber()}}<input id="input-{{.getName()}}" type="number" class="form-control" name="{{.getName()}}">{{/#.isTypeNumber()}}
{{#.isTypeBoolean()}}<input id="input-{{.getName()}}" type="checkbox" name="{{.getName()}}" value="true">{{/#.isTypeBoolean()}}
{{#.isTypeEnum()}}
{{#.isTypeSelection()}}
<select id="input-{{.getName()}}" class="form-control" name="{{.getName()}}">
{{#.getPossibleValues()}}<option>{{.}}</option>{{/.getPossibleValues()}}
</select>
{{/#.isTypeEnum()}}
{{/#.isTypeSelection()}}
{{#.getDescription()}}
<div class="form-text">{{.getDescription()}}</div>

View file

@ -70,7 +70,7 @@ function initDynamicModalForm(modalId, formTemplateId = null, templateID = null)
});
// Update dynamic inputs
$("#" + modalId + " select[name=type]").change(function(){
$("#" + modalId + " #"+formTemplateId).html(dynamicConf[formTemplateId][$(this).val()]);
$("#" + modalId + " #" + formTemplateId).html(dynamicConf[formTemplateId][$(this).val()]);
});
}

View file

@ -1,82 +1,74 @@
<div class="col-md-12 d-flex">
<div class="card flex-fill w-100">
<div class="card-header">
<div class="card-actions float-end">
<div class="dropdown show">
<a href="#" data-bs-toggle="dropdown" data-bs-display="static">
<i class="align-middle" data-feather="more-horizontal"></i>
</a>
<div class="card flex-fill w-100">
<div class="card-header">
<h5 class="card-title mb-0">Symbol Instances</h5>
</div>
<div class="dropdown-menu dropdown-menu-end">
<a class="dropdown-item" href="#">Action</a>
<a class="dropdown-item" href="#">Another action</a>
<a class="dropdown-item" href="#">Something else here</a>
</div>
<div class="card-body">
<div class="table-responsive">
<table class="table table-hover table-sm">
<thead>
<tr>
<th>Name</th>
<th>Exchange</th>
<th>
<div class="card-actions float-end">
<div class="btn-group float-end" role="group">
<button type="button" class="btn btn-success btn-sm"
data-bs-toggle="modal" data-bs-target="#symbolModal" data-action="create_symbol">
<i class="bi bi-plus"></i>
</button>
</div>
</div>
</th>
</tr>
</thead>
<tbody>
{{#symbols}}
<tr>
<td>{{.getName()}}</td>
<td>{{.getExchange().getName()}}</td>
<td>
<form method="POST">
<input type="hidden" name="id" value="{{.getId()}}">
<div class="btn-toolbar pull-right">
<button type="button" class="btn btn-default btn-sm" data-toggle="modal"
data-target="#symbolModal"
data-action="modify_symbol"
data-id="{{.getId()}}"
data-name="{{.getName()}}"
data-type="{{.getType()}}"
{{#.getDeviceConfigurator().getConfiguration()}}
data-{{.getName()}}="{{.getString()}}"
{{/.getDeviceConfigurator().getConfiguration()}}
>
<span class="glyphicon glyphicon-pencil"></span>
</button>
<button type="submit" class="btn btn-danger btn-sm" name="action" value="remove_symbol">
<span class="glyphicon glyphicon-trash"></span>
</button>
</div>
</form>
</td>
</tr>
{{/symbols}}
</tbody>
</table>
</div>
</div>
<h5 class="card-title mb-0">Recent Movement</h5>
</div>
<div class="card-body">
<div class="table-responsive">
<table class="table table-hover table-sm">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Configuration</th>
<th>
<button class="btn btn-default btn-sm pull-right" data-toggle="modal"
data-target="#symbolModal"
data-action="create_symbol">
<span class="glyphicon glyphicon-plus"></span>
</button>
</th>
</tr>
</thead>
<tbody>
{{#symbols}}
<tr>
<td>{{.getName()}}</td>
<td>{{.getType()}}</td>
<td>{{.getDeviceConfig()}}</td>
<td>
<form method="POST">
<input type="hidden" name="id" value="{{.getId()}}">
<div class="btn-toolbar pull-right">
<button type="button" class="btn btn-default btn-sm" data-toggle="modal"
data-target="#symbolModal"
data-action="modify_symbol"
data-id="{{.getId()}}"
data-name="{{.getName()}}"
data-type="{{.getType()}}"
{{#.getDeviceConfigurator().getConfiguration()}}
data-{{.getName()}}="{{.getString()}}"
{{/.getDeviceConfigurator().getConfiguration()}}
>
<span class="glyphicon glyphicon-pencil"></span>
</button>
<button type="submit" class="btn btn-danger btn-sm" name="action" value="remove_symbol">
<span class="glyphicon glyphicon-trash"></span>
</button>
</div>
</form>
</td>
</tr>
{{/symbols}}
</tbody>
</table>
</div>
</div>
</div>
</div>
<!------------- MODALS --------------->
<script>
$(function(){
$(function() {
initDynamicModalForm("symbolModal");
$("#exchange").change(function() {
alert(this.value);
});
});
</script>
@ -84,24 +76,35 @@
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"><span>&times;</span></button>
<h4 class="modal-title">Symbol</h4>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<form method="POST">
<div class="modal-body">
<input type="hidden" id="action" name="action">
<input type="hidden" id="id" name="id">
<div class="form-group">
<label class="control-label">Name:</label>
<input type="text" class="form-control" name="name">
<div>
<label class="control-label" for="exchange">Exchange:</label>
<select id="exchange" name="exchange" class="form-control">
<option></option>
{{#exchanges}}
<option value="{{.getId()}}">{{.getName()}}</option>
{{/exchanges}}
</select>
</div>
<div>
<label class="control-label" for="symbol">Symbol:</label>
<select id="symbol" name="symbol" class="form-control">
</select>
</div>
</div>
<div class="modal-footer">
<button type="reset" class="btn btn-default" data-dismiss="modal">Cancel</button>
<button type="reset" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
<button type="submit" class="btn btn-primary">Save</button>
</div>
</form>
</div>
</div>
</div>