Commit 11dfa27c authored by twj's avatar twj

Merge branch 'dev' of http://rungit.jxdsy.cn:10000/sugar/stock_new into dev

parents b63bea80 c93f3ccd
......@@ -2087,4 +2087,126 @@ if(!function_exists('get_between')) {
$substr = substr($input, strlen($start) + strpos($input, $start), (strlen($input) - strpos($input, $end)) * (-1));
return $substr;
}
//腾讯数据解析
if(!function_exists('jsonQuotation')) {
function jsonQuotation($item) {
$item[0] = isset($item[0])?substr(str_replace('v_','', $item[0]), 0, 2):'';//交易所代号
$item[80] = isset($item[30]) ? strtotime($item[30]) : time();
return $item;
}
}
/*
* 通过API接口获取全部股票列表
*/
if(!function_exists('apiStockList')) {
function apiStockList(){
$url = "http://".LOCAL_STOCK_HOST.":".LOCAL_STOCK_PORT."/api/market/getStockList";
$result = curls($url);
$data = json_decode($result, true);
$json = isset($data['data']) ? $data['data'] : [];
return $json;
}
}
/*
* 获取新浪热门行业
*/
if(!function_exists('getSinahy')) {
function getSinahy(){
$output = curl('https://vip.stock.finance.sina.com.cn/q/view/newSinaHy.php');
if($output){
$findme = '{"';
$pos = strpos($output, $findme) + 2;
$output = substr($output, $pos, -2);
$t2 = explode('","', mb_convert_encoding($output, 'utf-8', 'gbk'));
$res = array();
foreach ($t2 as $k => $v) {
$res[$k] = explode(',', substr(explode(':', $v)[1], 1));
}
return $res ?: false;
}else{
return false;
}
}
}
//新浪股票热门行业分类排行
if(!function_exists('getSinaNodeclass')) {
function getSinaNodeclass($node,$page=1,$num=50){
$url = 'https://vip.stock.finance.sina.com.cn/quotes_service/api/json_v2.php/Market_Center.getHQNodeData?page='.$page.'&num='.$num.'&sort=symbol&asc=1&node='.$node;
$json = curl($url);
$data = json_decode($json, true);
return $data ?: false;
}
}
/*
* 远程访问
*/
if (!function_exists('curls')) {
function curls($url, $data=[]) {
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl, CURLOPT_HTTPHEADER, array(
'Access-Token:' . LOCAL_TRADING_TOKEN,
'Client-Host:' . RedisUtil::getClientHost(),
));
curl_setopt($curl, CURLOPT_POST, 1);
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
curl_setopt($curl, CURLOPT_TIMEOUT, 10);
$res = curl_exec($curl);
curl_close($curl);
return $res;
}
}
/*
* 通过API接口获取行情
*/
if(!function_exists('getApiStock')) {
/**
* @param $code
* @param string $model
* @return array|mixed
*/
function getApiStock($code, $model='stock'){
//$recData['data'] = ThirdMarket($code,$model);
/**********************腾讯证券网********************/
$recData['data'] = TencentMarkets($code);
//$recData['data'] = east_market($code,$model);
switch ($model) {
case 'stock' ://单个股票
$stockData = isset($recData['data']) ? $recData['data'][0] : [];
break;
case 'stocks' ://多个股票
$stockData = isset($recData['data']) ? $recData['data'] : [];
break;
default :
$stockData = isset($recData['data']) ? $recData['data'][0] : [];
break;
}
return $stockData;
}
}
//腾讯数据获取
if(!function_exists('TencentMarkets')) {
function TencentMarkets($code){
$url = 'https://qt.gtimg.cn/q=' . $code;
//print_r($url);exit;
$output = curl($url);
$str = mb_convert_encoding($output, 'utf-8', 'gbk');
$str = str_replace(array("\r\n", "\r", "\n"), "", $str);
$t2 = explode('";', $str);
$json = [];
foreach ($t2 as $key => $val) {
$array = explode("~", $val);
if(isset($array[2])&&isset($array[3])&&isset($array[4])){
$json[] = jsonQuotation(explode("~", $val));
}else{
continue;
}
}
return $json;
}
}
}
\ No newline at end of file
<?php
// +----------------------------------------------------------------------
// | 常量定义表
// +----------------------------------------------------------------------
// 定义上传目录
define('DS', DIRECTORY_SEPARATOR);
define('UPLOAD_DIR', dirname(__DIR__) . DIRECTORY_SEPARATOR . 'public/uploads');
define('WS_SERVER_IP', (isset($this->request->server()['REMOTE_ADDR']) ? $this->request->server()['REMOTE_ADDR'] : ''));
/**
* 系统常量
* -- TOKEN_EXPIRE_TIME 用户登陆超时时间
* -- SEARCH_CACHE_EXPIRE_TIME 搜索缓存过期时间
* -- LOCAL_STOCK_TIMES 每隔几秒获取一次
* -- LOCAL_STOCK_COUNT 每次获取股票个数
* -- LOCAL_TRADING_TOKEN 行情数据请求TOKEN
* -- LOCAL_STOCK_HOST 行情数据请求地址
* -- LOCAL_STOCK_PORT 行情数据端口
* -- TRUST_ACTIVE_TIME 自动撤单时间,默认10分钟
* -- TRUST_MODEL_TIME............交易模式(T+1:1 ;T+0:0)
*/
define('TOKEN_EXPIRE_TIME', 60*60*24);//600 ------60*60*24=1天
define('SEARCH_CACHE_EXPIRE_TIME', 60*60*24);//1天
define('LOCAL_STOCK_TIMES', 3);//单位:秒
define('LOCAL_STOCK_COUNT', 800);
define('LOCAL_TRADING_TOKEN', 'cRQEEFzjDXASltkjvprHiBOSiNZNtRXP');
define('LOCAL_STOCK_HOST', 'stock.fcv3.1776174838209647.cn-hangzhou.fc.devsapp.net');
define('LOCAL_STOCK_PORT', 80);
define('TRUST_ACTIVE_TIME', 10*60);//默认10分钟
define('TRUST_MODEL_TIME', 1);// T+1:1 ; T+0:0
/**
* 定义Redis服务器常量
* -- REDIS_SERVER_IP 服务器IP地址
* -- REDIS_SERVER_PASSWORD 密码
*/
define('REDIS_SERVER_IP', '127.0.0.1');
define('REDIS_SERVER_PORT', 6379);
/**
* 根据type 获取资金明细的交易类型
*/
define('MONET_TYPE_NAME', [
'1'=>'充值成功',
'2'=>'提现冻结',
'3'=>'提现成功',
'4'=>'提现失败',
'5'=>'撤销提现',
'6'=>'提现退回',
'7'=>'追加保证金',
'8'=>'冻结保证金',
'9'=>'返还保证金',
'10'=>'邀请人推广返佣',
'11'=>'代理商佣金入账',
'12'=>'代理商分成入账',
'13'=>'提取佣金',
'14'=>'提取分成',
'15'=>'终止配资',
'16'=>'配资管理费',
'17'=>'递延费',
'18'=>'后台转账',
'19'=>'管理员操作',
'20'=>'配资结算',
'21'=>'配资审核不通过',
'22'=>'配资审核通过',
'23'=>'申请配资续期',
'24'=>'扩大配资审核通过',
'25'=>'扩大配资审核未通过',
'26'=>'追加保证金审核通过',
'27'=>'追加保证金审核未通过',
'28'=>'配资续期审核通过',
'29'=>'配资续期审核未通过',
'30'=>'配资提前终止审核通过',
'31'=>'配资提前终止审核未通过',
'32'=>'按月配资手续费自动扣款',
'33'=>'冻结金额',
'34'=>'扣除金额',
'80'=>'自动续期系统扣款',
'85'=>'提取盈利'
]);
define('RECORD_TYPE_NAME',[
'1'=>'购买股票扣款',
'2'=>'卖出股票回款',
'3'=>'购买股票扣款',
'4'=>'卖出股票回款',
'5'=>'卖出成功解除冻结',
'6'=>'买入成功解除冻结',
'7'=>'扣费用',
'8'=>'买入撤单解除冻结',
'9'=>'卖出撤单解除冻结',
'10'=>'追加保证金',
'11'=>'扩大配资',
'12'=>'提取盈利',
'13'=>'股票分红',
'14'=>'股票除权',
'15'=>'代扣股票利息税',
]);
<?php
namespace app\market\model;
use think\Model;
use think\Db;
use app\market\model\StockDeliveryOrder as Delivery;
//use util\RedisUtil;
/**
* 会员模型
*/
class StockPosition extends Model
{
// 设置当前模型对应的完整数据表名称
protected $name = 'stock_position';
// 自动写入时间戳
protected $autoWriteTimestamp = true;
/*
* 存储持仓记录
* $data 持仓数据
* $sub_id 子账号
* $lid 安全模式id号
* $user 证券账户
* $soure 证券来源
*/
public static function add_position_broker($data,$lid,$user,$soure){
$row=array();
foreach ($data as $k => $value) {
$row[$k]['lid'] = $lid;
$row[$k]['soruce'] = $soure;
$row[$k]['login_name'] = $user;
$row[$k]['gupiao_code'] = $value[0];
$row[$k]['gupiao_name'] = $value[1];
$row[$k]['count'] = $value[2];
$row[$k]['stock_count'] = $value[3];
$row[$k]['canbuy_count'] = $value[4];
$row[$k]['ck_price'] = $value[5];
$row[$k]['buy_average_price'] = $value[6];
$row[$k]['ck_profit_price'] = $value[7];
$row[$k]['now_price'] = $value[8];
$row[$k]['market_value'] = $value[9];
$row[$k]['ck_profit'] = $value[10];
$row[$k]['profit_rate'] = $value[11];
$row[$k]['buying'] = $value[12];
$row[$k]['selling'] = $value[13];
$row[$k]['gudong_code'] = $value[14];
$row[$k]['type'] = $value[15];
$row[$k]['jigou_type'] = $value[15];
$row[$k]['jiyisuo'] = $value[16]==0? "深交所":"上交所";
$row[$k]['info'] = $value[17];
}
$result = Db::name('stock_position_broker')->insertall($row,true);
return $result;
}
/*
* 返回子账号指定股票持仓数据-带最新市值
* $sub_id 子账号
*/
public static function getPositionFind($sub_id='',$code='')
{
if($sub_id) $map[] = ['sub_id','=',$sub_id];
if($code) $map[] = ['gupiao_code','=',$code];
$map[] = ['buying','=',0];
$res=Db::view('stock_position p')->view('stock_subaccount s','sub_account','s.id=p.sub_id')->where($map)->order('id desc')->select()->toArray();
foreach ($res as $k =>$v){
//查询股票最新行情
$Qdata = RedisUtil::getQuotationData($v['gupiao_code'],toMarket($v['gupiao_code']));
$res[$k]['now_price'] = $Qdata["Price"];
$res[$k]['code'] = $Qdata["code"];
$res[$k]['name'] = $Qdata["name"];
$res[$k]['market_value'] = round($Qdata["Price"] * $v['stock_count'],2);//最新市值
$res[$k]['ck_profit'] = $v['stock_count'] > 0 ? bcmul(strval($Qdata["Price"]-$v['buy_average_price']),strval($v['stock_count']),2) : 0;//参考浮动盈亏
//$res[$k]['profit_rate'] = $v['stock_count'] > 0 ? bcdiv(strval($res[$k]['ck_profit']),strval($v['buy_average_price']*$v['stock_count']*100),2) : 0;//盈亏比例
}
return $res;
}
/*
* 返回子账号和股票代码对应的持仓
* $sub_id 子账号
* $code 股票代码
*/
public static function getCodePosition($sub_id,$code){
$res=self::where(['sub_id'=>$sub_id,'gupiao_code'=>$code,'buying'=>0])->find();
if(empty($res)) return false;
$Qdata = RedisUtil::getQuotationData($code,toMarket($code),true);
$res['now_price'] = $Qdata["Price"];
$res['market_value'] = $Qdata["Price"]*$res['canbuy_count'];//最新市值
$res['ck_profit'] = $res['stock_count'] > 0 ? bcmul(strval($Qdata["Price"]-$res['buy_average_price']),strval($res['canbuy_count']),2) : 0;//参考浮动盈亏
//$res['profit_rate'] = $res['stock_count'] > 0 && $res['ck_profit'] ? bcdiv(strval($res['ck_profit']),strval($res['buy_average_price']*$res['canbuy_count']*100),2) : 0;//盈亏比例
return $res;
}
/*
* 返回子账号和股票代码对应持仓的可卖数量
* $sub_id 子账号
* $code 股票代码
*/
public static function getCanbuyCount($sub_id,$code){
$res = Db::name('stock_position')
->field('canbuy_count,stock_count')
->where(['sub_id'=>$sub_id,'gupiao_code'=>$code,'buying'=>0])
->find();
//print_r($res);exit;
if(empty($res)) return 0;
$res_d1 = Db::name('stock_delivery_order')
->where(['sub_id'=>$sub_id,'gupiao_code'=>$code,'status'=>1,'business_name'=>'证券买入'])
->whereDay('deal_date')
->sum('volume');
$res_d2 = Db::name('stock_delivery_order')
->where(['sub_id'=>$sub_id,'gupiao_code'=>$code,'status'=>0,'business_name'=>'证券卖出'])
->whereDay('deal_date')
->sum('volume');
//如果时T+0模式,就不计算当天的股票数量
if(TRUST_MODEL_TIME == 0) $res_d1 = $res_d2 = 0;
$res['canbuy_count'] = $res['stock_count'] - $res_d1 - $res_d2;
//print_r($res);exit;
return $res['canbuy_count'];
}
/*
* 添加卖出模拟持仓记录
* $data 持仓数据
* $sub_id 子账号
* $lid 安全模式id号
* $user 证券账户
* $soure 证券来源
* *************************************************************************************************************
*/
public static function sell_m_position($stockinfo,$count,$price,$sub_id,$model,$Trust_no,$commission,$Transfer,$stamp){
$position_res = self::getCodePosition($sub_id, $stockinfo["code"]);
if(empty($position_res)) return false;
if(!$model) $model = 2;
$data = $position_res;
$canbuy_count = $position_res['canbuy_count'] - $count;
$stock_count = $position_res['stock_count'] - $count;
$fee = $commission+$Transfer+$stamp;
if($canbuy_count>0){
if($model==1){
$data['canbuy_count'] = $canbuy_count;
}
if($model==2){
$new_price=round(($position_res['canbuy_count']*$position_res['buy_average_price']-$count*$price-$fee)/$canbuy_count,3);
$data['count'] =$stock_count;
$data['stock_count'] =$stock_count;
$data['canbuy_count'] = $canbuy_count;
$data['ck_price'] = $new_price;//参考成本价
$data['buy_average_price'] = $new_price;//买入均价
$data['ck_profit_price'] = $new_price;//参考盈亏成本价
$data['now_price'] = $stockinfo["Price"];//'当前价'
$data['market_value'] = $stockinfo["Price"]*$canbuy_count;//最新市值
$data['ck_profit'] = $canbuy_count >0 ? round(($stockinfo["Price"]-$new_price)*$canbuy_count,2) : 0;//参考浮动盈亏
$data['profit_rate'] = $canbuy_count >0 ? round($data['ck_profit']/($new_price*$canbuy_count)*100,2) : 0;//盈亏比例
}
$result = Db::name('stock_position')
->where(['sub_id'=>$sub_id,'gupiao_code'=>$stockinfo["code"]])
->where(['buying'=>0])
->update($data);
Log::write(date('y-m-d H:i:s',time())."::子账户".$sub_id."委托卖出".$count."股".$stockinfo["code"]."股票");
}elseif($canbuy_count==0){
if($model==2){
$info=Db::name('stock_temp')
->where(['sub_id'=>$sub_id])
->where(['gupiao_code'=>$stockinfo["code"]])
->where(['deal_no'=>null])
->find();
if(empty($info)) {
$result = Db::name('stock_position')
->where(['sub_id' => $sub_id, 'gupiao_code' => $stockinfo["code"]])
->where(['buying' => 0])
->delete();
}else{
$new_price=round(($position_res['stock_count']*$position_res['buy_average_price']-$count*$price-$fee)/$stock_count,3);
$data['count'] =$stock_count;
$data['stock_count'] =$stock_count;
$data['canbuy_count'] = 0;
$data['ck_price'] = $new_price;//参考成本价
$data['buy_average_price'] = $new_price;//买入均价
$data['ck_profit_price'] = $new_price;//参考盈亏成本价
$data['now_price'] = $stockinfo["Price"];//'当前价'
$data['market_value'] = $stockinfo["Price"]*$canbuy_count;//最新市值
$data['ck_profit'] = $canbuy_count >0 ? round(($stockinfo["Price"]-$new_price)*$canbuy_count,2) : 0;//参考浮动盈亏
$data['profit_rate'] = $canbuy_count >0 ? round($data['ck_profit']/($new_price*$canbuy_count)*100,2) : 0;//盈亏比例
$result = Db::name('stock_position')
->where(['sub_id'=>$sub_id,'gupiao_code'=>$stockinfo["code"]])
->where(['buying'=>0])
->update($data);
}
}elseif($model==1){
$data['canbuy_count']=0;
$result = Db::name('stock_position')
->where(['sub_id'=>$sub_id,'gupiao_code'=>$stockinfo["code"]])
->where(['buying'=>0])
->update($data);
}else{
$result = false;
}
}else{
$result = false;
}
return $result;
}
/*
* 存储模拟持仓记录
* $data 持仓数据
* $sub_id 子账号
* $lid 安全模式id号
* $user 证券账户
* $soure 证券来源
*/
public static function add_m_position($code,$count,$sub_id,$lid,$user,$soure,$ck_price,$Trust_no)
{
//if(!$count) return false;
//$canbuy = self::getCanbuyCount($sub_id,$code);
$stockinfo = RedisUtil::getQuotationData($code,toMarket($code));
$data = array();
$data[0]['sub_id'] = $sub_id;
$data[0]['lid'] = $lid;
$data[0]['soruce'] = $soure;
$data[0]['login_name'] = $user;
$data[0]['gupiao_code'] = $stockinfo["code"];
$data[0]['gupiao_name'] = $stockinfo["name"];
$data[0]['count'] = $count;
$data[0]['stock_count'] = $count;
$data[0]['canbuy_count'] = $count;
$data[0]['ck_price'] = self::calculate($sub_id,$code,'price');//参考成本价
$data[0]['buy_average_price'] = self::calculate($sub_id,$code,'average');//买入均价
$data[0]['ck_profit_price'] = '';//参考盈亏成本价
$data[0]['now_price'] = $stockinfo["Price"];//'当前价'
$data[0]['market_value'] = $stockinfo["Price"] * $count;//最新市值
$data[0]['ck_profit'] = $count > 0 ? bcmul(strval($stockinfo["Price"] - $ck_price),strval($count),2) : 0; //参考浮动盈亏
$data[0]['profit_rate'] = $count > 0 && $ck_price > 0 ? bcdiv(strval($data[0]['ck_profit']),strval($ck_price * $count * 100),2) : 0; //盈亏比例
$data[0]['buying'] = 0;//买入成功
$data[0]['selling'] = 0;//1、在途卖出
$data[0]['gudong_code'] = "";//股东代码 无法模拟暂时空
$data[0]['type'] = 0;//帐号类别
$data[0]['market'] = toMarket($code);//股票类别
$data[0]['jigou_type'] = 1;
$data[0]['jiyisuo'] = toMarket($code)=='SZ'? "深交所":"上交所";//交易所
$data[0]['info'] = "";
$position = self::getCodePosition($sub_id, $code);
/***********************************************************************************/
if(TRUST_MODEL_TIME === 1){ // 交易模式为T+1时,不能立即更新可卖数量
unset($data[0]['canbuy_count']);
}
/***********************************************************************************/
if(!empty($position)){
$result = self::where(['id'=>$position['id']])->update($data[0]);
}else{
$result = self::strict(false)->insert($data[0],true);
}
return $result;
}
public static function calculate($sub_id,$code,$variable)
{
if(!$sub_id || !$code || !$variable) return 0;
switch ($variable) {
case 'price':
$order = Db::name('stock_delivery_order')->where(['sub_id' => $sub_id, 'gupiao_code' => $code,'status' => 1,'business_name' => '证券买入']);
$amount = $order->sum('liquidation_amount');
$volume = $order->sum('volume');
$result = bcdiv(strval($amount),strval($volume),3);
break;
case 'average':
$order = Db::name('stock_delivery_order')->where(['sub_id' => $sub_id, 'gupiao_code' => $code,'status' => 1,'business_name' => '证券买入']);
$amount = $order->sum('residual_quantity');
$volume = $order->sum('volume');
$result = bcdiv(strval($amount),strval($volume),3);
break;
default:
$result = 0;
break;
}
return $result;
}
}
\ No newline at end of file
......@@ -47,7 +47,7 @@ class AccountInfo extends ThinkModel
*/
public static function getAccountInfo($id)
{
$data_list = cache('stock_account_info');
$data_list = cache('stock_account_info'.$id);
if (!$data_list) {
$where['id'] =$id;
$lid = Db::name('stock_account')->where($where)->column('lid');
......@@ -59,7 +59,7 @@ class AccountInfo extends ThinkModel
if(!is_null($data_list)){
// 非开发模式,缓存数据
if (config('develop_mode') == 0) {
cache('stock_account_info', $data_list);
cache('stock_account_info'.$id, $data_list);
}
}
}
......
......@@ -398,6 +398,7 @@ class Borrow extends ThinkModel
$start=date('Y-m-d',$dataInfo['verify_time']);
$data['borrow_duration']=$data['borrow_duration']-1;
$end_time=getEndDay($start, $data['borrow_duration'],festival());
break;
default:
if(getEndDay2('now', festival())===1&&time()<mktime(14,45)){
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment