| Current Path : /var/www/html/aipa/backend/modules/cryptoaverage/views/crypto-average/ |
| Current File : /var/www/html/aipa/backend/modules/cryptoaverage/views/crypto-average/index.php |
<?php
use yii\helpers\Html;
use yii\helpers\Url;
use yii\bootstrap\Modal;
use backend\modules\cryptoaverage\models\CryptoParameter;
/* @var $this yii\web\View */
/* @var $searchModel backend\models\CryptoAverageSearch */
/* @var $dataProvider yii\data\ActiveDataProvider */
/* @var $data yii\data\ActiveDataProvider */
/* @var $coin backend\controllers\CryptoAverageController */
$this->title = Yii::t('app', 'Crypto Averages');
$this->params['breadcrumbs'][] = $this->title;
$this->registerJsFile('https://bossanova.uk/jspreadsheet/v4/jexcel.js');
$this->registerJsFile('https://jsuites.net/v4/jsuites.js');
$this->registerJsFile('https://cdn.jsdelivr.net/gh/alpinejs/alpine@v2.x.x/dist/alpine.min.js');
$this->params['extra-asset']['CSS'][] = 'plugins/toastr/toastr.min.css';
$this->params['extra-asset']['JS'][] = 'plugins/toastr/toastr.min.js';
$url = Url::to(['/cryptoaverage/crypto-average']);
$urlFormula = Url::to(['/cryptoaverage/crypto-average/formula-template']);
$urlSave = Url::to(['/cryptoaverage/crypto-average/save-spread']);
$urlPull = Url::to(['/cryptoaverage/crypto-average/api']);
$this->registerJs(
<<<JS
var changed = function(instance, cell, x, y, value) {
var cellName = jexcel.getColumnNameFromId([x,y]);
$('#log').append('New change on cell ' + cellName + ' to: ' + value + '<br>');
}
var beforeChange = function(instance, cell, x, y, value) {
// spread.setValue(cell, value)
var cellName = jexcel.getColumnNameFromId([x,y]);
$('#log').append('The cell ' + cellName + ' will be changed<br>');
}
var insertedRow = function(el, rowNumber, numOfRows, rowRecords, insertBefore) {
$('#log').append('Row added<br>');
}
var insertedColumn = function(instance) {
$('#log').append('Column added<br>');
}
var deletedRow = function(instance) {
$('#log').append('Row deleted<br>');
}
var deletedColumn = function(instance) {
$('#log').append('Column deleted<br>');
}
var sort = function(instance, cellNum, order) {
var order = (order) ? 'desc' : 'asc';
$('#log').append('The column ' + cellNum + ' sorted by ' + order + '<br>');
}
var resizeColumn = function(instance, cell, width) {
$('#log').append('The column ' + cell + ' resized to width ' + width + ' px<br>');
}
var resizeRow = function(instance, cell, height) {
$('#log').append('The row ' + cell + ' resized to height ' + height + ' px<br>');
}
var selectionActive = function(instance, x1, y1, x2, y2, origin) {
var cellName1 = jexcel.getColumnNameFromId([x1, y1]);
var cellName2 = jexcel.getColumnNameFromId([x2, y2]);
$('#log').append('The selection from ' + cellName1 + ' to ' + cellName2 + '<br>');
}
var loaded = function(instance) {
$('#log').append('New data is loaded<br>');
$('.jexcel_content').css('box-shadow', 'none')
}
var moveRow = function(instance, from, to) {
$('#log').append('The row ' + from + ' was move to the position of ' + to + ' <br>');
}
var moveColumn = function(instance, from, to) {
$('#log').append('The col ' + from + ' was move to the position of ' + to + ' <br>');
}
var blur = function(instance) {
$('#log').append('The table ' + $(instance).prop('id') + ' is blur<br>');
}
var focus = function(instance) {
$('#log').append('The table ' + $(instance).prop('id') + ' is focus<br>');
}
var paste = function(instance, data) {
$('#log').append('Paste on the table ' + $(instance).prop('id') + '<br>');
}
// var data = [
// ['2021-03-04 00:00:00', 0.045243, 237, 'BUY', '=IF(D1=="BUY",(B1*C1),0)', '=IF(D1=="SELL",(B1*C1),0)', '=IF(D1=="BUY",C1,0-C1)', '=E1-F1', '=IF(D1=="BUY",B1,"")', '=IF(D1=="BUY",C1,"")', '=IF((H1/G1)<MIN(I1:I2),"-",(H1/G1))', 0],
// ['2021-03-04 00:01:00', 0.044741, 224, 'BUY', '=IF(D1=="BUY",(B2*C2),0)', '=IF(D2=="SELL",(B2*C2),0)', '=IF(D2=="BUY",C2+G1,G1-C2)', '=H1+(E2-F2)', '=IF(D2=="BUY",B2,"")', '=IF(D2=="BUY",C2,"")', '=IF((H2/G2)<MIN(I1:I2),"-",(H2/G2))', '=IF(D2=="SELL",F2-(K1*C2),0)'],
// ];
var data = [];
var w = $('.wrapper-content').width() - 20;
var spread = jspreadsheet(document.getElementById('spreadsheet'), {
data:data,
rowResize:false,
columnDrag:false,
tableOverflow: true,
tableWidth:w + 'px',
copyCompatibility:true,
allowInsertRow: true,
allowManualInsertRow: false,
columns: [
{ title: 'Date Time', type: 'calendar', width:'150', options: { format:'DD/MM/YYYY HH24:MI', time:1 } },
{ title: 'Price', type: 'numeric', width:'100' },
{ title: 'Qty', type: 'numeric', width:'80' },
{ title: 'Type', type: 'dropdown', width:'80', source:[ "BUY", "SELL"] },
{ title: 'Buy', type: 'numeric', width:'80' },
{ title: 'Sell', type: 'numeric', width:'80', readOnly:false },
{ title: 'Net', type: 'numeric', width:'80' },
{ title: 'Cumulative', type: 'numeric', width:'90' },
{ title: 'Buy Price', type: 'numeric', width:'80' },
{ title: 'Buy Qty', type: 'numeric', width:'80' },
{ title: 'Average', type: 'numeric', width:'80' },
{ title: 'Profit/Loss', type: 'numeric', width:'0' },
{ title: 'ID', type: 'numeric', width:'0', readOnly:true},
{ title: 'OrderId', type: 'numeric', width:'100' },
],
onchange: changed,
onbeforechange: beforeChange,
oninsertrow: insertedRow,
oninsertcolumn: insertedColumn,
ondeleterow: deletedRow,
ondeletecolumn: deletedColumn,
onselection: selectionActive,
onsort: sort,
onresizerow: resizeRow,
onresizecolumn: resizeColumn,
onmoverow: moveRow,
onmovecolumn: moveColumn,
onload: loaded,
onblur: blur,
onfocus: focus,
onpaste: paste,
onbeforeinsertcolumn: function(a,b,c) {
},
contextMenu: function(obj, x, y, e) {
var items = [];
if (y == null) {
} else {
// Insert new row
if (obj.options.allowInsertRow == true) {
var max = obj.getData().length;
var row = obj.getData().length + 1;
items.push({
title:'Add new row',
onclick:function() {
$.get('$urlFormula' + '?row=' + parseInt(row) + '&prev=' + (parseInt(row) - 1) + '&max=' + parseInt(row), (res) => {
//obj.data.push(res)
console.log(parseInt(row))
obj.insertRow(1, parseInt(row));
obj.setRowData(max, res)
})
}
});
}
if (obj.options.allowDeleteRow == true) {
items.push({
title:obj.options.text.deleteSelectedRows,
onclick:function() {
obj.deleteRow(obj.getSelectedRows().length ? undefined : parseInt(y));
//obj.refresh();
}
});
}
if (x) {
if (obj.options.allowComments == true) {
items.push({ type:'line' });
var title = obj.records[y][x].getAttribute('title') || '';
items.push({
title: title ? obj.options.text.editComments : obj.options.text.addComments,
onclick:function() {
obj.setComments([ x, y ], prompt(obj.options.text.comments, title));
}
});
if (title) {
items.push({
title:obj.options.text.clearComments,
onclick:function() {
obj.setComments([ x, y ], '');
}
});
}
}
}
// Save
if (obj.options.allowExport) {
items.push({
title: 'Save',
shortcut: 'Ctrl + S',
onclick: function () {
obj.download();
}
});
}
}
// Line
items.push({ type:'line' });
return items;
}
});
window.spread = spread
//wait for formula loaded
setTimeout(function() {
window.spread.setData($data)
}, 500);
$('.coin-drop').change(function(){
window.location = '$url?coin=' + this.value
})
$('#save').click(()=>{
var data = spread.getData()
$.post('$urlSave?coin=$coin', {data: JSON.stringify(data)}, (res) => {
if(res.success){
toastr["success"]("Data saved")
//reload page
window.location.reload()
}
});
})
JS
);
$this->registerJs(
<<<JS
//----formula-----
const PRICE_COL = 'B';
const QTY_COL = 'C';
const TYPE_COL = 'D';
const BUY_COL = 'E';
const SELL_COL = 'F';
const NET_COL = 'G';
const CUM_COL = 'H';
const BUY_PRICE_COL = 'I';
const BUY_QTY_COL = 'J';
const AVERAGE_COL = 'K';
const PROFIT_COL = 'L';
var BUY = function(row) {
var price = window.spread.getValue(PRICE_COL + row);
var qty = window.spread.getValue(QTY_COL + row);
var type = window.spread.getValue(TYPE_COL + row);
if (type == 'BUY') {
return (price * qty)
}
return 0;
}
var SELL = function(row) {
var price = window.spread.getValue(PRICE_COL + row);
var qty = window.spread.getValue(QTY_COL + row);
var type = window.spread.getValue(TYPE_COL + row);
if (type === 'SELL') {
return (price * qty)
}
return 0;
}
var NET = function(row) {
var type = window.spread.getValue(TYPE_COL + row);
var qty = window.spread.getValue(QTY_COL + row);
var pnet = window.spread.getValue(NET_COL + (row - 1));
if (type === 'BUY') {
if (row == 1) {
return qty
}
return parseInt(qty) + parseInt(pnet)
} else {
if (row == 1) {
return 0 - qty
}
//negatif
// if(pnet < 0) {
// return parseInt(pnet) + parseInt(qty)
// }
return parseInt(pnet) - parseInt(qty)
}
return 0;
}
var CUM = function(row) {
var buy = window.spread.getValue(BUY_COL + row);
var sell = window.spread.getValue(SELL_COL + row);
var pcum = window.spread.getValue(CUM_COL + (row - 1));
if (row == 1) {
return buy - sell
} else {
return parseFloat(pcum) + parseFloat(buy - sell)
}
}
var BUY_PRICE = function(row) {
var type = window.spread.getValue(TYPE_COL + row);
if(type == 'BUY') {
return window.spread.getValue(PRICE_COL + row);
}
return 0
}
var BUY_QTY = function(row) {
var type = window.spread.getValue(TYPE_COL + row);
if(type == 'BUY') {
return window.spread.getValue(QTY_COL + row);
}
return 0;
}
var buyprice = 0 ;
var CAVERAGE = function(row, min) {
var cum = window.spread.getValue(CUM_COL + row);
var prevavg = window.spread.getValue(AVERAGE_COL + (row - 1));
var type = window.spread.getValue(TYPE_COL + row);
var net = window.spread.getValue(NET_COL + row);
var sell = window.spread.getValue(SELL_COL + row);
var buyprice = spread.getColumnData(1);
var min = Math.min(...buyprice)
if(type == 'BUY') {
return parseFloat(cum) / parseFloat(net)
} else if(type == 'SELL') {
return (prevavg * cum) / (cum - sell)
}
return 0;
// if( (cum/net) < min ) {
// return 0;
// } else {
// return parseFloat(cum) / parseFloat(net)
// }
}
var PROFIT = function(row, min) {
var fcol = [
BUY_COL + row,
SELL_COL + row,
NET_COL + row,
CUM_COL + row,
BUY_PRICE_COL + row,
BUY_QTY_COL + row,
AVERAGE_COL + row,
PROFIT_COL + row
]
spread.formula[QTY_COL + row] = fcol
spread.formula[TYPE_COL + row] = fcol
spread.formula[PRICE_COL + row] = fcol
spread.formula[CUM_COL + (row - 1)] = [
CUM_COL + row,
AVERAGE_COL + row
];
spread.formula[AVERAGE_COL + (row - 1)] = [PROFIT_COL + row]
var type = window.spread.getValue(TYPE_COL + row);
var sell = window.spread.getValue(SELL_COL + row);
var qty = window.spread.getValue(QTY_COL + row);
var pave = window.spread.getValue(AVERAGE_COL + (row - 1));
if(type == 'SELL') {
if(row > 1) {
return sell - parseFloat(pave * qty)
}
}
return 0
}
JS
,
YII::$app->view::POS_HEAD
);
?>
<link rel="stylesheet" href="https://bossanova.uk/jspreadsheet/v4/jexcel.css" type="text/css" />
<link rel="stylesheet" href="https://jsuites.net/v4/jsuites.css" type="text/css" />
<link rel="stylesheet" href="https://bossanova.uk/jspreadsheet/v4/jexcel.themes.css" type="text/css" />
<!-- <link rel="stylesheet" href="https://bossanova.uk/jspreadsheet/v4/jexcel.datatables.css" type="text/css" /> -->
<style>
.mail-search {
max-width: 500px;
}
#dropSearch_chosen>.chosen-single {
min-width: 200px;
height: 30px !important;
}
.pagination {
float: right;
}
#w0-filters {
display:none;
}
.tr-item {
cursor:pointer;
}
.table td {
white-space: nowrap;
}
.jexcel > tbody > tr > td.readonly {
color:blue;
}
.coin-drop {
width:150px;
/* max-width:min-content; */
display:inline-block;
vertical-align: top;
}
.coin-label{
vertical-align: super;
}
.btn-default.m-b{
line-height: 23px;
}
.jexcel_content::-webkit-scrollbar-thumb {
border-radius: 10px;
background:gray;
}
:root {
--jexcel_header_color: #000;
--jexcel_header_color_highlighted: #000;
--jexcel_header_background: #f3f3f4;
--jexcel_header_background_highlighted: #90caf9;
--jexcel_content_color: #000;
--jexcel_content_color_highlighted: #000;
--jexcel_content_background: #fff;
--jexcel_content_background_highlighted: rgba(0,0,0,0.05);
--jexcel_menu_background: #fff;
--jexcel_menu_background_highlighted: #ebebeb;
--jexcel_menu_color: #555;
--jexcel_menu_color_highlighted: #555;
--jexcel_menu_box_shadow: 2px 2px 2px 0px rgba(143, 144, 145, 1);
--jexcel_border_color: #ccc;
--jexcel_border_color_highlighted: #000;
--active_color: #007aff;
}
.jexcel > tbody > tr > td, .jexcel > thead > tr > td {
padding:10px;
font-weight:100;
}
.jexcel > tbody > tr > td:nth-child(3),
.jexcel > tbody > tr > td:nth-child(4),
.jexcel > tbody > tr > td:nth-child(5) {
color:#2196f3
}
</style>
<div class="wrapper wrapper-content">
<div x-data="loadData()">
<span class="coin-label">SYMBOL :- </span>
<?= Html::dropDownList('crypto', $coin, CryptoParameter::getSymbol(), ['prompt' => '--Select--','class' => 'form-control coin-drop', 'x-model'=> 'symbol'])?>
<?= Html::button('<i class="fa fa-refresh"></i> '. Yii::t('app', 'Pull record'), ['class' => 'btn btn-sm btn-default m-b', 'id' => 'pull-record', '@click'=>"openModal()" , 'disabled' => empty($_GET['coin'])]) ?>
<?= Html::button('<i class="fa fa-save"></i> '. Yii::t('app', 'Save record'), ['class' => 'btn btn-sm btn-primary m-b', 'id' => 'save']) ?>
<div class="alert alert-info" x-show="!symbol"> Please Select Symbol First</div>
<?php
/* start modal */
Modal::begin([
'header' => Yii::t('app', '<h4>Add Record From Binance</h4>'),
'size' => 'modal-lg',
'id' => 'add-modal'
]);
?>
<div class="row">
<!-- <div class="col-md-5">
<div class="form-group">
<label class="font-normal">Start Date</label>
<input type="datetime-local" class="form-control" x-model="startTime">
</div>
</div>
<div class="col-md-5">
<div class="form-group">
<label class="font-normal">End Date</label>
<input type="datetime-local" class="form-control" x-model="endTime">
</div>
</div>
<div class="col-md-2" style="line-height:76px;">
<button class="btn btn-default" @click="pullData()">Pull Record</button>
</div> -->
<div class="col-md-12" style="text-align: right">
<button class="btn btn-success" @click="selectAll()"><i class="fa fa-check"></i> Select all</button>
<button class="btn btn-warning" @click="deselectAll()"><i class="fa fa-times"></i> Deselect all</button>
<button class="btn btn-primary" @click="addRecord()"><i class="fa fa-plus"></i> Add Record</button>
</div>
</div>
<div class="table-responsive">
<table class="table table-striped">
<thead>
<tr>
<th></th>
<th>Symbol </th>
<th>OrderId </th>
<th>Price</th>
<th>Quantity</th>
<th>Quote</th>
<th>Side</th>
<th>Time</th>
</tr>
</thead>
<tbody>
<template x-for="(item, index) in items" :key="index">
<tr x-show="existData.indexOf(item.orderId) == -1">
<td><input type="checkbox" class="checks" name="checkbox[]" :value="JSON.stringify(item)"></td>
<td><small x-text="item.symbol"></small></td>
<td><small x-text="item.orderId"></small></td>
<td><small x-text="item.price"></small></td>
<td><small x-text="item.qty"></small></td>
<td><small x-text="item.quoteQty"></small></td>
<td><small x-text="item.isBuyer ? 'BUY' : 'SELL'"></small></td>
<td><small x-text="item.time"></small></td>
</tr>
</template>
<tr x-show="noRecord">
<td colspan="7" align="center"> No records founds</td>
</tr>
</tbody>
</table>
</div>
<script type="text/javascript">
function loadData(){
let data = <?= $data ?>;
let exist = data.map(v => v[v.length - 1]);
return {
items: [],
startTime: null,
endTime: null,
noRecord: true,
symbol: '<?= $coin ?>',
existData: exist,
openModal() {
$('#add-modal').modal('show')
this.pullData()
},
deselectAll() {
$('.checks').each( (i, v)=> {
v.checked = false;
})
},
selectAll() {
$('.checks').each( (i, v)=> {
v.checked = true;
})
},
addRecord(){
let record = []
let exist = spread.getJson()
if(!exist) {
return
}
record = exist;
$('.checks').each( (i, v) => {
if(v.checked) {
let r = [];
let j = JSON.parse(v.value)
let side = j.isBuyer ? 'BUY' : 'SELL'
r.push(j.time);
r.push(j.price);
r.push(j.qty);
r.push(side);
r.push('=BUY(ROW())')
r.push('=SELL(ROW())')
r.push('=NET(ROW())')
r.push('=CUM(ROW())')
r.push('=BUY_PRICE(ROW())')
r.push('=BUY_QTY(ROW())')
r.push('=CAVERAGE(ROW())')
r.push('=PROFIT(ROW())')
r.push(null)
r.push(j.orderId)
record.push(r)
}
})
window.spread.setData(record)
},
pullData() {
$.ajax('<?= $urlPull ?>?symbol=<?= $coin ?>', {
type: 'POST',
dataType: 'json',
contentType: 'application/json',
data: JSON.stringify({ orderId: 1234})
})
.done(data => {
$('#add-modal').modal('show')
if(!data.success){
alert('Failed to get response from the server');
return;
}
if(data.data.length > 0) {
this.noRecord = false
}
const record = data.data.filter( (v) => true)
this.items = record
})
.fail((e) => {
console.error('Fail to connect the data server:', e.statusText);
});
}
}
}
</script>
<?php Modal::end(); ?>
</div>
<div class="ibox <?= empty($_GET['coin']) ? 'hide' : '' ?>" >
<div class="mail-box b-r-md" style="padding:10px">
<div id="spreadsheet"></div>
</div>
</div>
<!-- <div id="log"></div> -->
</div>