첫 번째 커밋

This commit is contained in:
javamon
2025-12-06 22:31:19 +09:00
commit 849a100fa9
33 changed files with 6613 additions and 0 deletions

View File

View File

@@ -0,0 +1,370 @@
# -*- coding: utf-8 -*-
import sys
from collectors.collector import Collector
import logging
# import API
from lib.pybinancefutures import *
# curl
import json
import datetime, time
import requests
from pandas import DataFrame
import pandas as pd
from bs4 import BeautifulSoup
from db import DB
# access
# DPob3MlV51nb55D6OovjKTNRiyoiMWihX2phcunUNxI73Z7gSyo2ALX87dxcmuXB
# secret
# qgd5YHf4TiWvD8KjOL1qoPz9QX354mYMIoQ6FBt5VCv1tswQq3X6eGaFFrHZ7a7a
angel = 'power'
class Binance(Collector):
def __init__(self, access=None, secret=None):
self.remaining_req = {}
self._heaeder = {}
self._mathod = 'get'
self._finance = 'crypto' # 금융 종목
self._name = 'binance' # 거래소 이름
self.leverage = 1
self._standard_price = 0
self._temp_api_url = 'https://fapi.binance.com/fapi/v1/' # 임시 api 주소
self._market = MarketData()
if secret is not None:
self._api = Client(access, secret)
self._api_url = self._temp_api_url
self._set_allow_items()
# get filtered markets
self.markets = self._load_markets() # 테스트때 주석
'''
For Cron Funtions
'''
# 바이낸스 기준 시총 정의
def _get_standard_trade_price(self, markets=None):
p_list = []
for m in self._market.ticker_price_24h():
p = m['lastPrice']
v = m['volume']
p_list.append(float(p)*float(v))
p_list.sort(reverse=True)
return float(p_list[1] - p_list[1] * 0.01)
def _return_list_filted_markets(self):
filtered_list = []
for m in self._market.ticker_price_24h():
s = m['symbol']
p = m['lastPrice']
v = m['volume']
f_if = False
# 리플 제외
if 'XRP' in s:
continue
# 허용 아이템 조건
for i in self.allow_items:
if i == s.replace('USDT', ''):
f_if = True
# 24시간 거래금액 및 종목 가격 제한 조건
# f_if = float(p) * float(v) > self._standard_price \
# and float(p) > float(100)
if f_if:
item = {
'market': str(s),
'acc_trade_price_24h': float(p) * float(v), # 거래 총 금액
'acc_trade_volume_24h': float(v), # 거래량
}
filtered_list.append(item)
return filtered_list
def _save_market_list_to_db(self, markets):
for m in markets:
self._save_item_data_to_item_table(self._finance, # 금융
self._name, # 거래소
m['market'], # 종목
m['acc_trade_price_24h'], # 24시간 거래 금액
m['acc_trade_volume_24h'] # 24시간 거래량
)
def _load_markets(self):
# DB에서 종목이 없을 경우 아래 로직 실행
try:
markets = self._return_list_filted_markets()
# set exchange min marget cap(시총)
self._standard_price = self._get_standard_trade_price(markets)
# 거래소 기본정보 DB 저장 (거래 기준가, api_url 등)
self._add_exchange_info_to_db(self._finance, self._name, self._standard_price, self._api_url)
# 종목 리스트 DB 저장
self._save_market_list_to_db(markets)
return markets
except Exception as e:
logging.error(e)
return self._load_markets()
# raise Exception(e) # for dev
def save_current_min_data(self, market):
time_type = 'minute'
data = self.get_history_data(market, time_type)
self._save_to_db_from_collectors_dataframe(self.finance, self._name, market, data, time_type)
def save_current_hour_data(self, market):
time_type = 'hour'
data = self.get_history_data(market, time_type)
self._save_to_db_from_collectors_dataframe(self.finance, self._name, market, data, time_type)
def save_current_day_data(self, market):
time_type = 'day'
data = self.get_history_data(market, time_type)
self._save_to_db_from_collectors_dataframe(self.finance, self._name, market, data, time_type)
def get_history_data(self, symbol="BTCUSDT", interval="hour", rm_last=True):
int2type = {
"day": "1d",
"hour12": "12h",
"hour6": "6h",
"hour4": "4h", # custom hour
"hour": "1h",
"minute30": "30m",
"minute15": "15m",
"minute10": "15m",
"minute5": "5m",
"minute3": "3m",
"minute": "1m",
}
# set symbol
self._market.symbol = symbol
data = self._market.candles_data(int2type[interval], None, None, 1500)
columns = ['Date', 'Open', 'High', 'Low', 'Close', 'Volume', 'Close_Time',
'Quote_Asset_Volume', 'Number_of_Trades', 'Taker_Buy_Base_Asset_Volume',
'Taker_Buy_Quote_Asset_Volume', 'Ignore']
df = DataFrame(data, columns=columns)
self.data_columns_init(df)
if not df.empty:
# Convert timestamp to date format
dates = [datetime.datetime.fromtimestamp(int(d) / 1000).strftime("%Y-%m-%d %H:%M:%S")
for d in df['Date'].values]
# df.loc[:, 'Date'] = df['Date']\
# .apply(lambda d: datetime.datetime.fromtimestamp(int(d)/1000).strftime("%Y-%m-%d %H:%M:%S"))
# Set needs columns
df = df[['Open', 'High', 'Low', 'Close', 'Volume']]
# Remove last candle
if rm_last:
df = df[:-1]
df.loc[:, symbol] = pd.Series(dates)
df = df.set_index(symbol)
# return df
return df.astype(float)
else:
return None
'''
For Trade Funtions
'''
def get_current_price(self, symbol):
self._market.symbol = symbol
recent_price = self._market.ticker_price_symbol(symbol)
if recent_price:
return recent_price[0]['price']
return None
def get_position_info(self):
return self._api.position_info()
def get_last_price_from_orderbook(self, symbol, position, cnt=0):
if cnt > 10:
return None, None
self._market.symbol = symbol
order_book = self._market.ticker_orderbook_symbol(symbol)
cnt += 1
for b_d in order_book:
if b_d['symbol'] in symbol:
if position == 'long':
return float(b_d['bidPrice'])
elif position == 'short':
return float(b_d['askPrice'])
time.sleep(1)
return self.get_last_price_from_orderbook(symbol, position, cnt)
def get_trading_fee(self):
return float(0.02)
# get_position_balance
def get_position_balance(self, symbol='USDT'):
time.sleep(1)
for b in self._api.position_info():
if str(b['symbol']) == str(symbol):
return float(abs(float(b['positionAmt'])))
return False
def get_balance(self, symbol='USDT'):
for b in self._api.balance():
if str(b['symbol']) == str(symbol):
return self.cal_ceil(b['positionAmt'], 5)
return 0
def get_now_amount(self, symbol):
res = {}
for b in self._api.balance():
if str(b['asset']) == 'USDT':
res['KRW'] = '{:.8f}'.format(float(b['withdrawAvailable']))
elif str(b['asset']) in symbol:
res[b['asset']] = '{:.8f}'.format(float(b['withdrawAvailable']))
return res
def get_all_seeds(self):
for b in self._api.balance():
if b['asset'] == 'USDT':
return '{:.8f}'.format(float(b['balance']))
# BinanceFuturesPy
def order_long(self, symbol, order=None, cnt=0):
self._api.symbol = symbol
# 레버리지 설정
self._api.change_leverage(self.leverage)
# 이전 주문 취소
self.order_cancel(order)
target_price = self.get_last_price_from_orderbook(symbol, 'long')
seeds = float(self.get_now_amount(symbol)['KRW'])
amount = self.get_position_balance(symbol)
if not amount > 0:
amount = self.cal_ceil(seeds / target_price, 5)*int(self.leverage)
if not amount > 0:
return False, None
if cnt > 100:
# 시장가 매수
order = self._api.new_order(side='BUY',
quantity=amount,
orderType='MARKET')
return True, {'symbol': symbol, 'target_price': target_price, 'amount': amount, 'seeds': seeds}
else:
# 지정가 매수
order = self._api.new_order(side='BUY',
quantity=amount,
price=target_price,
orderType='LIMIT',
timeInForce='GTC')
if order is None or 'msg' in order:
print('주문 오류 -', order['msg'])
return False, None
time.sleep(2)
ordered = self._api.query_order(order['orderId'])
if ordered['origQty'] != ordered['executedQty']:
cnt += 1
return self.order_long(symbol, order, cnt)
seeds = float(self.get_now_amount(symbol)['KRW'])
# seeds = self.get_now_amount(symbol)['KRW']
return True, {'symbol': symbol, 'target_price': target_price, 'amount': amount, 'seeds': seeds}
def order_short(self, symbol, order=None, cnt=0):
# for test
# return True, {'symbol': symbol, 'target_price': 8952000, 'amount': 1, 'seeds': 22000}
self._api.symbol = symbol
# 레버리지 설정
self._api.change_leverage(self.leverage)
# 이전 주문 취소
self.order_cancel(order)
target_price = self.get_last_price_from_orderbook(symbol, 'short')
seeds = float(self.get_now_amount(symbol)['KRW'])
amount = self.get_position_balance(symbol)
if not amount > 0:
amount = self.cal_ceil(seeds / target_price, 5)*int(self.leverage)
if not amount > 0:
return False, None
if cnt > 100:
# 시장가 매도
self._api.new_order(side='SELL',
quantity=amount,
orderType='MARKET')
seeds = self.get_now_amount(symbol)['KRW']
return True, {'symbol': symbol, 'target_price': target_price, 'amount': amount, 'seeds': seeds}
else:
order = self._api.new_order(side='SELL',
quantity=amount,
price=target_price,
orderType='LIMIT',
timeInForce='GTC')
if order is None or 'msg' in order:
print('주문 오류 -', order['msg'])
return False, None
time.sleep(2)
ordered = self._api.query_order(order['orderId'])
if ordered['origQty'] != ordered['executedQty']:
cnt += 1
return self.order_short(symbol, order, cnt)
seeds = float(self.get_now_amount(symbol)['KRW'])
# seeds = self.get_now_amount(symbol)['KRW']
return True, {'symbol': symbol, 'target_price': target_price, 'amount': amount, 'seeds': seeds}
def order_cancel(self, order=None):
if order is not None:
return self._api.cancel_order(order['orderId'])
return False

View File

@@ -0,0 +1,343 @@
# -*- coding: utf-8 -*-
import sys
from collectors.collector import Collector
import logging
# import API
import pybithumb
# curl
import json
import datetime, time
import requests
from pandas import DataFrame
from bs4 import BeautifulSoup
from db import DB
class Bithumb(Collector):
def __init__(self, access=None, secret=None):
self.remaining_req = {}
self._heaeder = {}
self._mathod = 'get'
self._finance = 'crypto' # 금융 종목
self._name = 'bithumb' # 거래소 이름
self.leverage = 1
self._standard_price = 0
self._temp_api_url = 'https://api.bithumb.com/' # 임시 api 주소
# self._api = pybithumb
if secret is None:
self._api = pybithumb.Bithumb
else:
self._api = pybithumb.Bithumb(access, secret)
self._api_url = self._temp_api_url
self._set_allow_items()
# get filtered markets
self.markets = self._load_markets() # 테스트때 주석
# 빗썸 거래 기준금액 정의
def _get_standard_trade_price(self, markets=None):
p_list = []
for m in markets:
res = pybithumb.get_market_detail(m)
# 종목 가격 제한 조건 추가 2019-11-12 => 잡코 방지
p_list.append(float(res[3])*float(res[4]))
# if res['status'] == '0000':
# p_list.append(float(res['data']['acc_trade_value_24H']))
p_list.sort(reverse=True)
return float(p_list[0] - p_list[0] * 0.01)
# return float(p_list[1] - p_list[1] * 0.01)
def _return_list_filted_markets(self, markets):
filtered_list = []
for m in markets:
f_if = False
# 리플 제외
if 'XRP' in m:
continue
res = pybithumb.get_market_detail(m)
# 허용 아이템 조건
for i in self.allow_items:
if i == m.replace('KRW-', ''):
f_if = True
# 24시간 거래금액 및 종목 가격 제한 조건
# f_if = float(res[3]) * float(res[4]) > self._standard_price \
# and float(res[3]) > float(100)
if f_if:
item = {
'market': 'KRW-' + str(m),
'acc_trade_price_24h': float(res[3]) * float(res[4]), # 거래 총 금액
'acc_trade_volume_24h': float(res[4]), # 거래량
}
filtered_list.append(item)
return filtered_list
def _save_market_list_to_db(self, markets):
for m in markets:
self._save_item_data_to_item_table(self._finance, # 금융
self._name, # 거래소
m['market'], # 종목
m['acc_trade_price_24h'], # 24시간 거래 금액
m['acc_trade_volume_24h'] # 24시간 거래량
)
def _load_markets(self):
# DB에서 종목이 없을 경우 아래 로직 실행
try:
markets = self._api.get_tickers()
# set exchange min volume
self._standard_price = self._get_standard_trade_price(markets)
filtered_markets = self._return_list_filted_markets(markets)
# 거래소 기본정보 DB 저장 (거래 기준가, api_url 등)
self._add_exchange_info_to_db(self._finance, self._name, self._standard_price, self._api_url)
# 종목 리스트 DB 저장
self._save_market_list_to_db(filtered_markets)
return filtered_markets
except Exception as e:
logging.error(e)
raise Exception(e) # for dev
return markets
def get_symbol_for_chart_view(self, market):
s = market.split('-')
return s[1] + '_' + s[0]
def save_current_min_data(self, market):
time_type = 'min'
data = self.get_history_data(self.get_symbol_for_chart_view(market), 'minute')[:-1]
self._save_to_db_from_collectors_dataframe(self.finance, self._name, market, data, time_type)
def save_current_hour_data(self, market):
time_type = 'hour'
data = self.get_history_data(self.get_symbol_for_chart_view(market), 'hour')[:-1]
self._save_to_db_from_collectors_dataframe(self.finance, self._name, market, data, time_type)
def save_current_day_data(self, market):
time_type = 'day'
data = self.get_history_data(self.get_symbol_for_chart_view(market), 'day')[:-1]
self._save_to_db_from_collectors_dataframe(self.finance, self._name, market, data, time_type)
def _swap_item_name(self, symbol):
symbol = str(symbol).replace('-', '_')
if 'KRW' in symbol.split('_')[0]:
s = symbol.split('_')
r_symbol = '_'.join([s[1], s[0]])
return r_symbol
return symbol
def get_history_data(self, symbol="BTC_KRW", interval="day", rm_last=True):
symbol = self._swap_item_name(symbol)
int2type = {
# "hour12": "12H",
# "hour6": "06H",
# "hour4": "01H", # custom hour
# "hour": "01H",
"day": "24H",
"hour12": "01H",
"hour6": "01H",
"hour4": "01H", # custom hour
"hour": "01H",
"minute30": "30M",
"minute10": "10M",
"minute5": "05M",
"minute3": "03M",
"minute": "01M",
}
url = "https://m.bithumb.com/trade/chart/{}".format(symbol)
resp = requests.get(url)
html = resp.text
# parsing coin type
string = html.split("COIN = ")[1].split(";")[0]
coin = json.loads(string)
tk2ct = {v['symbol_name']: k for k, v in coin['C0100'].items()}
# parsing xcoin name
selector = "#barcodeForm > input[name=csrf_xcoin_name]"
soup = BeautifulSoup(html, 'html5lib')
xcoin_name = soup.select(selector)[0]['value']
url = "https://m.bithumb.com/trade_history/chart_data"
headers = {
"cookie": 'csrf_xcoin_name={}'.format(xcoin_name),
"x-requested-with": "XMLHttpRequest"
}
symbol = symbol.replace("KRW", "")
symbol = symbol.replace("_", "")
data = {
"coinType": tk2ct[symbol],
"crncCd": "C0100",
"tickType": int2type[interval],
"csrf_xcoin_name": xcoin_name
}
resp = requests.post(url, data=data, headers=headers).json()
for x in resp['data']:
x[0] = datetime.datetime.fromtimestamp(x[0] / 1000)
columns = [symbol, 'open', 'close', 'high', 'low', 'volume']
df = DataFrame(resp['data'], columns=columns)
df = df.set_index(symbol)
if not df.empty:
# Remove last candle
if rm_last:
df = df[:-1]
self.data_columns_init(df)
if interval == 'hour4' or interval == 'hour6' or interval == 'hour12':
return self.packaging_data_per_time_unit(df, interval)
return df.astype(float)
else:
return None
def get_current_price(self, symbol):
symbol = self._swap_item_name(symbol)
return self._api.get_current_price(symbol)
def get_last_price_from_orderbook(self, symbol, position):
symbol = self._swap_item_name(symbol)
res = self._api.get_orderbook(symbol)
if res:
if position == 'long':
return int(res['bids'][0]['price'])
elif position == 'short':
return int(res['asks'][0]['price'])
return None, None
def get_trading_fee(self):
return self._api.get_trading_fee()
def get_all_balance(self, symbol='ALL'):
return self._api.get_balance(symbol)
def get_now_amount(self, symbol):
s = symbol.replace('KRW', '').replace('-', '')
res = {}
c, u, k, u = self.get_all_balance(s)
res[symbol] = '{:.8f}'.format(c)
res['KRW'] = int(k)-int(u)
return res
# https://github.com/sharebook-kr/pybithumb
# https://wikidocs.net/21887
def order_long(self, symbol, order=None, cnt=0):
# for test
# return True, {'symbol': symbol, 'target_price': 8723000, 'amount': 1, 'seeds': 20000}
# 이전 주문 취소
self.order_cancel(order)
target_price = self.get_last_price_from_orderbook(symbol, 'long')
s = symbol.replace('KRW', '').replace('-', '')
seeds = self.get_now_amount(symbol)['KRW']
amount = float('{:.4f}'.format(seeds/target_price, 4))
if cnt > 100:
# 시장가 매수
self._api.buy_market_order(s, amount)
return True, {'symbol': symbol, 'target_price': target_price, 'amount': amount, 'seeds': seeds}
else:
# 지정가 매수
order = self._api.buy_limit_order(s, target_price, amount)
if order is None or 'message' in order:
print('주문 오류 -', order['message'])
return False
time.sleep(1)
if self._api.get_outstanding_order(order) is not None:
cnt += 1
return self.order_long(symbol, order, cnt)
return True, {'symbol': symbol, 'target_price': target_price, 'amount': amount, 'seeds': seeds}
def order_short(self, symbol, order=None, cnt=0):
# for test
# return True, {'symbol': symbol, 'target_price': 8952000, 'amount': 1, 'seeds': 22000}
# 이전 주문 취소
self.order_cancel(order)
target_price = self.get_last_price_from_orderbook(symbol, 'short')
s = symbol.replace('KRW', '').replace('-', '')
amount = float(format(self._api.get_balance(s)[0], ".4f"))
if not amount > 0:
return True
if cnt > 100:
# 시장가 매도
self._api.sell_market_order(s, amount)
seeds = self.get_now_amount(symbol)['KRW']
return True, {'symbol': symbol, 'target_price': target_price, 'amount': amount, 'seeds': seeds}
else:
# 지정가 매도
order = self._api.sell_limit_order(s, target_price, amount)
if order is None or 'message' in order:
print('주문 오류 -', order['message'])
return False
time.sleep(1)
if self._api.get_outstanding_order(order) is not None:
cnt += 1
return self.order_short(symbol, order, cnt)
seeds = self.get_now_amount(symbol)['KRW']
return True, {'symbol': symbol, 'target_price': target_price, 'amount': amount, 'seeds': seeds}
def order_cancel(self, order=None):
if order is not None:
return self._api.cancel_order(order)
return False
# 포지션 종료 => 매도
def close_position(self, symbol):
return self.order_short(symbol)

View File

@@ -0,0 +1,169 @@
# -*- coding: utf-8 -*-
from collectors.collector import Collector
# Logging
import logging
# Exchage API
import pyupbit
import sys
# 거래금액 기준은 거래소 아이템 중 상위 3개에서 3번째의 종목 최소 거래금액 기준으로 정한다. # 종목 추가 기능을 추가한다.
# 상위 3개 종목 기본 거래종목 후보로 추가(데이터 수집) => 조건 만족 시 거래
# 1. 거래량
# 2. 변동폭
# 3. 수익성(시뮬레이터 결과 기반) : 머신러닝, 인디케이터 등 포함된 결과
# 거래 종목에서 제외 => 거래량, 변동폭, 수익성
# 거래 후보 종목에서 제외 => 거래량
# 거래량 기준 => 거래소 추가 시 상위 3개 종목 중 3번째 데이터 기준 => 사용자가 변경 가능 및 종목 추가 가능
class Upbit(Collector):
def __init__(self):
self._auth = {
'access': 'IdO6IXpgC07 XB2KWoID37jxvFXgpLMkxZRTxHViI',
'secret': 'QteNfsNZly1kZ1t3MGAc9bOxMDiIouozuQCZVVJI',
}
self.remaining_req = {}
self._heaeder = {}
self._mathod = 'get'
self._finance = 'crypto' # 금융 종목
self._name = 'upbit' # 거래소 이름
self.leverage = 1
self._standard_price = 0
self._temp_api_url = 'https://api.upbit.com/v1/' # 임시 api 주소
# get api url from db
self._api_url = self._get_api_url()
self._api = pyupbit
self._secret_api = pyupbit.Upbit(self._auth['access'], self._auth['secret'])
self._set_allow_items()
# get filtered markets
self.markets = self._load_markets() # 테스트때 주석
def set_key_data(self, access, secret):
self._secret_api = pyupbit.Upbit(access, secret)
# 업비트 거래 기준금액 정의
def _get_standard_trade_price(self, markets = None):
if markets == None:
markets = self._get_data_all_markets()
p_list = []
for m in markets :
c_type = self._get_currency_type(m['market'])
# 원화 거래
if c_type is 1:
p_list.append(int(m['acc_trade_price_24h']))
p_list.sort(reverse=True)
return int(p_list[0] - p_list[0] * 0.01)
# return int(p_list[2] - p_list[2] * 0.01)
def _get_data_all_markets(self):
market_all = self._get_market_all()
if market_all is None:
return
markets = []
for market in market_all:
markets.append(market['market'])
URL = self._api_url + 'ticker?markets=%s' % str(','.join(markets))
return self._get(URL)
def _return_list_filted_markets(self, markets):
filtered_list = []
for m in markets:
c_type = self._get_currency_type(m['market'])
f_if = False
# except ripple
if 'XRP' in m['market']:
continue
# 허용 아이템 조건
for i in self.allow_items:
if i == m['market'].replace('KRW-', ''):
f_if = True
# 24시간 거래금액 및 종목 가격 제한 조건
# f_if = int(m['acc_trade_price_24h']) > self._standard_price \
# and float(m['low_price']) > float(100)
# 원화 거래 항목으로 제한
if c_type is 1 and f_if:
filtered_list.append(m)
return filtered_list
def _save_market_list_to_db(self, markets):
for m in markets :
self._save_item_data_to_item_table(self._finance, # 금융
self._name, # 거래소
m['market'], # 종목
m['acc_trade_price_24h'], # 24시간 거래 금액
m['acc_trade_volume_24h'] # 24시간 거래량
)
def _load_markets(self):
# DB에서 종목이 없을 경우 아래 로직 실행
try:
markets = self._get_data_all_markets()
# set exchange min price
self._standard_price = self._get_standard_trade_price(markets)
filtered_markets = self._return_list_filted_markets(markets)
# 거래소 기본정보 DB 저장 (거래 기준가, api_url 등)
self._add_exchange_info_to_db(self._finance, self._name, self._standard_price, self._api_url)
# 종목 리스트 DB 저장
self._save_market_list_to_db(filtered_markets)
return filtered_markets
except Exception as e:
logging.error(e)
raise Exception(e) # for dev
return markets
def _get_market_all(self):
'''
마켓 코드 조회
업비트에서 거래 가능한 마켓 목록
https://docs.upbit.com/v1.0/reference#%EB%A7%88%EC%BC%93-%EC%BD%94%EB%93%9C-%EC%A1%B0%ED%9A%8C
:return: json array
'''
URL = self._api_url + 'market/all'
return self._get(URL)
def save_current_min_data(self, market):
time_type = 'min'
data = self._api.get_ohlcv(market, interval="minute1")[:-1]
self._save_to_db_from_collectors_dataframe(self.finance, self._name, market, data, time_type)
def save_current_hour_data(self, market):
time_type = 'hour'
data = self._api.get_ohlcv(market, interval="minute60")[:-1]
self._save_to_db_from_collectors_dataframe(self.finance, self._name, market, data, time_type)
def save_current_day_data(self, market):
time_type = 'day'
data = self._api.get_ohlcv(market, interval="day")[:-1]
self._save_to_db_from_collectors_dataframe(self.finance, self._name, market, data, time_type)

View File

@@ -0,0 +1,5 @@
[.ShellClassInfo]
InfoTip=<EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><EFBFBD><C2B6><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>˴ϴ<CBB4>.
IconFile=C:\Program Files\Google\Drive\googledrivesync.exe
IconIndex=16