2019102152 김다빈

Modify README and Add LICENSE & Add images

1 +Copyright (c) [2021] 김다빈,이가원
2 +
3 +Permission is hereby granted, free of charge, to any person obtaining a copy
4 +of this software and associated documentation files (the "Software"), to deal
5 +in the Software without restriction, including without limitation the rights
6 +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 +copies of the Software, and to permit persons to whom the Software is
8 +furnished to do so, subject to the following conditions:
9 +
10 +The above copyright notice and this permission notice shall be included in all
11 +copies or substantial portions of the Software.
12 +
13 +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 +SOFTWARE.
...\ No newline at end of file ...\ No newline at end of file
1 -#Trading Service 1 +<div align="center">
2 + <a href="https://github.com/othneildrew/Best-README-Template">
3 + <img src="images/logo.png" alt="Logo" width="80" height="80">
4 + </a>
2 5
3 -./config/dev.js 생성 필요 6 + <h3 align="center">업비트 암호화폐 자동 매매 서비스</h3>
4 -module.exports = { 7 + </p>
5 - mongoURI:{mongoURI} 8 +</div>
6 -} 9 +
7 -.env 파일 생성 후 access_key와 secret_key 할당 필요 10 +## About The Project
11 +<img src="images/about01.jpg" alt="about" width="80" height="80">
12 +<h4>24시간 시세가 변하는 암호화폐를 위한 자동 매매 서비스<br/></h4>
13 +해당 서비스를 만든 이유 <br/>
14 +● 24시간 가격변동이 있지만 사람이 하루종일 보고 있을 수는 없다.<br/>
15 +● 매매 기준을 정해두어도 이성적인 판단을 못하고 감정적으로 매매를 할 수 있다.<br/>
16 +● 일상샐활을 하면서 고정적인 수익을 얻을 수 있다.<br/>
17 +
18 +#### DB Schema
19 +* User
20 + - uid : 유저의 고유 아이디
21 + - krw_balance : 보유 원화
22 + - market : 보유 암호화폐 이름
23 + - count : 매수 횟수
24 + - avg_buy_price : 매수 평균가
25 + - volume : 보유 암호화폐 갯수
26 +
27 +* Coin
28 + - tid : 거래량별 암호화폐 순위
29 + - name : 암호화폐 이름
30 + - korean_name : 암호화폐 한글 이름
31 + - acc_trade_price_24h : 24시간 거래대금
32 + - current_price : 현재 암호화폐 가격
33 + - up_count : 5분 간격 연속 상승 횟수
34 + - down_count : 5분 간격 연속 하락 횟수
35 +
36 +### Built With
37 +* [Node.js](https://nodejs.org/)
38 +
39 +### Installation
40 +1. repository를 clone한다.
41 +```sh
42 + git clone http://khuhub.khu.ac.kr/Crypto/Crypto_trade_bot.git
43 +```
44 +2. NPM package들을 설치한다.
45 +```sh
46 + npm install
47 +```
48 +3. 해당 프로젝트는 aws ec2와 ssl인증서를 사용한다. 개인 PC에서 작동하려면 domain과 sslport를 지우고 express.app을 사용해서 서버를 작동시키면 된다.(이 경우 4번은 생략)
49 +4. 최상위 폴더의 index.js의 domain과 sslport를 본인 domain과 sslport로 변경한다.
50 +```js
51 +const domain = "{your domain}";
52 +const sslport = {your port};
53 +```
54 +5. https://cloud.mongodb.com/ 가입 후 db connect url을 복사한다.
55 +6. /config 폴더에 dev.js 파일 추가
56 +```js
57 + module.exports = {
58 + mongoURI:"복사한 connect url"
59 + }
60 +```
61 +7. https://upbit.com/service_center/open_api_guide 에서 access_key와 secret_key를 발급받는다.
62 +8. https://developers.line.biz/en/services/messaging-api/ 에서 line message-api를 생성하고 channel access token을 복사한다.
63 +9. 3번에서 입력한 도메인을 webhook url로 설정해준다.(4번을 생략했다면 webhook url에 본인 네트워크망IP를 입력)
64 +10. 프로젝트 최상위 폴더에 .env 파일 추가
65 +```env
66 + access_key={upbit에서 발급 받은 access_key}
67 + secret_key={upbit에서 발급 받은 secret_key}
68 + token={line message-api 의 channel access token}
69 + userid={테스트 알림을 받을 line userid}
70 +```
71 +## Usage
72 +프로젝트 최상위 폴더에서 명령어 실행
73 +```sh
74 + nodemon
75 +```
76 +<img src="images/first.jpg" alt="first" width="80" height="80">
77 +<img src="images/second.jpg" alt="second" width="80" height="80">
78 +
79 +## Roadmap
80 +- [x] Add get_marketname
81 +- [x] Add get_marketInfo
82 +- [x] Add price_comparison
83 +- [x] Add transaction_coin
84 +- [x] Add latest_repeat
85 +- [x] Add send the order breakdown to the user
86 +- [x] Add send the asset to the user
87 +- [x] Add Whenever a sale is signed, the details of the signing are sent.
88 +
89 +## Contributing
90 +
91 +1. 프로젝트를 fork 하세요.
92 +2. 여러분의 feature 브랜치를 만들어 주세요.(`git checkout -b feature/{function}`)
93 +3. 변경사항을 commit 해주세요.(`git commit -m 'Add some function`)
94 +4. 원격 브랜치로 push 해주세요.(`git push origin feature/{function}`)
95 +5. pull request를 보내주세요.
96 +
97 +## License
98 +[MIT License](http://khuhub.khu.ac.kr/Crypto/Crypto_trade_bot/blob/master/LICENSE)
99 +
100 +<!-- CONTACT -->
101 +## Contact
102 +
103 +이름 - [@김다빈,이가원](https://github.com/dogsoft0937) - dogsoft0937@khu.ac.kr,juneee0864@gmail.com <br/>
104 +프로젝트 주소: [http://khuhub.khu.ac.kr/Crypto/Crypto_trade_bot](http://khuhub.khu.ac.kr/Crypto/Crypto_trade_bot)
105 +## Acknowledgments
106 +
107 +* [upbit-reference](https://docs.upbit.com/reference)
108 +* [line-reference](https://developers.line.biz/en/reference/messaging-api/)
......
...@@ -12,8 +12,7 @@ const HTTPS = require('https'); ...@@ -12,8 +12,7 @@ const HTTPS = require('https');
12 const domain = "2019102152.osschatbot.ga" 12 const domain = "2019102152.osschatbot.ga"
13 const sslport = 23023; 13 const sslport = 23023;
14 const TARGET_URL = 'https://api.line.me/v2/bot/message/reply' 14 const TARGET_URL = 'https://api.line.me/v2/bot/message/reply'
15 -const TOKEN = process.env.token; 15 +
16 -var userid = process.env.userid;
17 16
18 const bodyParser = require('body-parser'); 17 const bodyParser = require('body-parser');
19 const crypto = require('crypto'); 18 const crypto = require('crypto');
...@@ -24,6 +23,8 @@ const sign = require('jsonwebtoken').sign ...@@ -24,6 +23,8 @@ const sign = require('jsonwebtoken').sign
24 const access_key = process.env.access_key; 23 const access_key = process.env.access_key;
25 const secret_key = process.env.secret_key; 24 const secret_key = process.env.secret_key;
26 const server_url = "https://api.upbit.com" 25 const server_url = "https://api.upbit.com"
26 +const TOKEN = process.env.token;
27 +const userid = process.env.userid;
27 28
28 var delay_count=1; 29 var delay_count=1;
29 30
...@@ -76,7 +77,7 @@ function get_asset(market) { ...@@ -76,7 +77,7 @@ function get_asset(market) {
76 // hold_coin[data[i].currency]={avg_buy_price:data[i].avg_buy_price,volume:data[i].balance,current_price:candle[0].trade_price}; 77 // hold_coin[data[i].currency]={avg_buy_price:data[i].avg_buy_price,volume:data[i].balance,current_price:candle[0].trade_price};
77 } 78 }
78 } 79 }
79 - resolve({ pre_asset: pre_asset.toFixed(0), current_asset: current_asset.toFixed(0), profit_data: (current_asset - pre_asset).toFixed(0), yield_data: ((current_asset - pre_asset) / pre_asset * 100).toFixed(2) }); 80 + resolve({ pre_asset: pre_asset.toFixed(0).replace(/\B(?<!\.\d*)(?=(\d{3})+(?!\d))/g, ","), current_asset: current_asset.toFixed(0).replace(/\B(?<!\.\d*)(?=(\d{3})+(?!\d))/g, ","), profit_data: (current_asset - pre_asset).toFixed(0).replace(/\B(?<!\.\d*)(?=(\d{3})+(?!\d))/g, ",") , yield_data: Number((current_asset - pre_asset) / pre_asset * 100).toFixed(2).replace(/\B(?<!\.\d*)(?=(\d{3})+(?!\d))/g, ",") });
80 } else if (market == "coin") { 81 } else if (market == "coin") {
81 var hold_coin = new Object(); 82 var hold_coin = new Object();
82 83
...@@ -132,9 +133,14 @@ async function get_marketName() { ...@@ -132,9 +133,14 @@ async function get_marketName() {
132 } 133 }
133 async function transaction_coin(coin_name, side, volume, price, ord_type, first = true) { 134 async function transaction_coin(coin_name, side, volume, price, ord_type, first = true) {
134 var volume = volume; 135 var volume = volume;
135 - if (side == "ask" && volume == "") { 136 + var avg_buy_price=0,market="";
137 + if (side == "ask") {
136 await User.findOne({ market: coin_name }).then((result) => { 138 await User.findOne({ market: coin_name }).then((result) => {
137 - volume = String(result.volume); 139 + if(volume == ""){
140 + volume = String(result.volume);
141 + }
142 + avg_buy_price=result.avg_buy_price;
143 + market=result.market.split('-')[1];
138 }).catch(err => { console.log(err.error) }); 144 }).catch(err => { console.log(err.error) });
139 } 145 }
140 const body = { 146 const body = {
...@@ -144,7 +150,6 @@ async function transaction_coin(coin_name, side, volume, price, ord_type, first ...@@ -144,7 +150,6 @@ async function transaction_coin(coin_name, side, volume, price, ord_type, first
144 price: price, 150 price: price,
145 ord_type: ord_type, 151 ord_type: ord_type,
146 } 152 }
147 - console.log(body);
148 //시장가 매수인 경우 price를 얼마치 살건지 입력 153 //시장가 매수인 경우 price를 얼마치 살건지 입력
149 //시장가 매도인경우 volume에 몇개를 팔건지 입력 154 //시장가 매도인경우 volume에 몇개를 팔건지 입력
150 const query = queryEncode(body) 155 const query = queryEncode(body)
...@@ -170,8 +175,10 @@ async function transaction_coin(coin_name, side, volume, price, ord_type, first ...@@ -170,8 +175,10 @@ async function transaction_coin(coin_name, side, volume, price, ord_type, first
170 }, delay) 175 }, delay)
171 }) 176 })
172 var my_asset = await asset(1000); 177 var my_asset = await asset(1000);
173 - if(my_asset.market&&my_asset.market.avg_buy_price){ 178 +
174 - lookup_order(result.uuid,my_asset.market.avg_buy_price); 179 + if(avg_buy_price!=0){
180 + console.log(avg_buy_price);
181 + lookup_order(result.uuid,avg_buy_price,market);
175 }else{ 182 }else{
176 lookup_order(result.uuid); 183 lookup_order(result.uuid);
177 } 184 }
...@@ -332,7 +339,6 @@ async function price_comparison(candle, user_data = null, isbuying = false) { ...@@ -332,7 +339,6 @@ async function price_comparison(candle, user_data = null, isbuying = false) {
332 }).catch(err => { console.log(err); }) 339 }).catch(err => { console.log(err); })
333 } 340 }
334 }else{ 341 }else{
335 - console.log(촛불);
336 console.log(result); 342 console.log(result);
337 } 343 }
338 }) 344 })
...@@ -371,7 +377,7 @@ async function latest_repeat(t1) { ...@@ -371,7 +377,7 @@ async function latest_repeat(t1) {
371 let today = new Date(); 377 let today = new Date();
372 let minutes = today.getMinutes(); 378 let minutes = today.getMinutes();
373 let seconds = today.getSeconds(); 379 let seconds = today.getSeconds();
374 - if (seconds == 0) { 380 + if (seconds ==0) {
375 // if (minutes == 0 && seconds == 0) { 381 // if (minutes == 0 && seconds == 0) {
376 clearInterval(check_time); 382 clearInterval(check_time);
377 sort_info = (await sort_data()); 383 sort_info = (await sort_data());
...@@ -401,7 +407,7 @@ async function latest_repeat(t1) { ...@@ -401,7 +407,7 @@ async function latest_repeat(t1) {
401 } 407 }
402 }, 1000); 408 }, 1000);
403 } 409 }
404 -function lookup_order(uuid,avg_buy_price=0) { 410 +function lookup_order(uuid,avg_buy_price=0,market="") {
405 const body = { 411 const body = {
406 uuid: uuid 412 uuid: uuid
407 } 413 }
...@@ -441,21 +447,21 @@ function lookup_order(uuid,avg_buy_price=0) { ...@@ -441,21 +447,21 @@ function lookup_order(uuid,avg_buy_price=0) {
441 volume = volume.toFixed(8).toString().replace(/\B(?<!\.\d*)(?=(\d{3})+(?!\d))/g, ","); 447 volume = volume.toFixed(8).toString().replace(/\B(?<!\.\d*)(?=(\d{3})+(?!\d))/g, ",");
442 funds = funds.toFixed(0).toString().replace(/\B(?<!\.\d*)(?=(\d{3})+(?!\d))/g, ","); 448 funds = funds.toFixed(0).toString().replace(/\B(?<!\.\d*)(?=(\d{3})+(?!\d))/g, ",");
443 if(avg_buy_price!=0){ 449 if(avg_buy_price!=0){
444 - trading_notice(body.side, price, funds, volume,yield_data); 450 + trading_notice(body.side, price, funds, volume,yield_data,market);
445 }else{ 451 }else{
446 trading_notice(body.side, price, funds, volume); 452 trading_notice(body.side, price, funds, volume);
447 } 453 }
448 }) 454 })
449 return; 455 return;
450 } 456 }
451 -function trading_notice(side, price, funds, volume,yield_data=0) { 457 +function trading_notice(side, price, funds, volume,yield_data=0,market="") {
452 var messages = new Array(); 458 var messages = new Array();
453 if (side == "bid") { 459 if (side == "bid") {
454 messages.push({ "type": "text", "text": "매수 주문이 체결되었습니다." }); 460 messages.push({ "type": "text", "text": "매수 주문이 체결되었습니다." });
455 - messages.push({ "type": "text", "text": `체결 금액 : ${funds}원\n체결 수량 : ${volume}개\n체결 평균가 : ${price}원\n` }); 461 + messages.push({ "type": "text", "text": `${market}\n체결 금액 : ${funds}원\n체결 수량 : ${volume}개\n체결 평균가 : ${price}원\n` });
456 } else { 462 } else {
457 messages.push({ "type": "text", "text": "매도 주문이 체결되었습니다." }); 463 messages.push({ "type": "text", "text": "매도 주문이 체결되었습니다." });
458 - messages.push({ "type": "text", "text": `체결 금액 : ${funds}원\n체결 수량 : ${volume}개\n체결 평균가 : ${price}원\n수익률 : ${yield_data}%` }); 464 + messages.push({ "type": "text", "text": `${market}\n체결 금액 : ${funds}원\n체결 수량 : ${volume}개\n체결 평균가 : ${price}원\n수익률 : ${yield_data}%` });
459 } 465 }
460 466
461 var TARGET_URL = 'https://api.line.me/v2/bot/message/push'; 467 var TARGET_URL = 'https://api.line.me/v2/bot/message/push';
......
1 const mongoose=require('mongoose'); 1 const mongoose=require('mongoose');
2 -
3 const coinSchema=mongoose.Schema({ 2 const coinSchema=mongoose.Schema({
4 tid:{ 3 tid:{
5 type:Number, 4 type:Number,
...@@ -20,11 +19,14 @@ const coinSchema=mongoose.Schema({ ...@@ -20,11 +19,14 @@ const coinSchema=mongoose.Schema({
20 type:Number, 19 type:Number,
21 required:true 20 required:true
22 }, 21 },
23 - count:{ 22 + up_count:{
23 + type:Number,
24 + default:0
25 + },
26 + down_count:{
24 type:Number, 27 type:Number,
25 default:0 28 default:0
26 } 29 }
27 }) 30 })
28 -
29 const Coin=mongoose.model("Coin",coinSchema); 31 const Coin=mongoose.model("Coin",coinSchema);
30 module.exports={Coin}; 32 module.exports={Coin};
...\ No newline at end of file ...\ No newline at end of file
......
1 const mongoose=require('mongoose'); 1 const mongoose=require('mongoose');
2 -
3 const userSchema=mongoose.Schema({ 2 const userSchema=mongoose.Schema({
4 uid:{ 3 uid:{
5 type:Number 4 type:Number
...@@ -11,7 +10,7 @@ const userSchema=mongoose.Schema({ ...@@ -11,7 +10,7 @@ const userSchema=mongoose.Schema({
11 type:String, 10 type:String,
12 }, 11 },
13 count:{ 12 count:{
14 - type:Number, 13 + type:Number
15 }, 14 },
16 avg_buy_price:{ 15 avg_buy_price:{
17 type:Number 16 type:Number
...@@ -20,6 +19,5 @@ const userSchema=mongoose.Schema({ ...@@ -20,6 +19,5 @@ const userSchema=mongoose.Schema({
20 type:Number 19 type:Number
21 } 20 }
22 }) 21 })
23 -
24 const User=mongoose.model("User",userSchema); 22 const User=mongoose.model("User",userSchema);
25 -module.exports={User}; 23 +module.exports={User};
...\ No newline at end of file ...\ No newline at end of file
......