def pick(date_obj, **kwargs): date_tw = RocDateConverter().get_roc_date_by_datetime(date_obj) min_volume = kwargs.pop('min_volume', 1 * 1000) max_volume = kwargs.pop('max_volume', 10 * 1000) min_price = kwargs.pop('min_price', 12) max_price = kwargs.pop('max_price', 1000) min_change_percent = kwargs.pop('min_chagne_percent', 0.03) consolidation_days = kwargs.pop('consolidation_days', 20) retriever = Retriever() data_path = retriever.data_dir file_list = (f for f in listdir(data_path) if search_filename(f) is not None) winners = [] for filename in file_list: # system('clear') # print('{} -- {}'.format(filename, ', '.join(winners)), end="\r") search_stock_code = re.search('(\w+).csv$', filename) stock_code = search_stock_code.group(1) line_number = retriever.search_line_number_by_date(stock_code, date_tw) if line_number is None: continue try: check = retriever.check_model_1(stock_code, line_number, min_volume=min_volume, max_volume=max_volume, min_price=min_price, max_price=max_price, min_change_percent=min_change_percent, consolidation_days=consolidation_days) except RetrieverException: continue if check: winners.append(stock_code) return winners
def main(): parser = argparse.ArgumentParser() parser.add_argument('stock_codes', nargs='*', help="股票代號") args = parser.parse_args() stock_codes = args.stock_codes #print(stock_codes) retriever = Retriever(stock_codes) retriever.put_mapping_by_stock_codes() retriever.dump_to_es()
def main(): retriever = Retriever() data_dir = retriever.data_dir file_list = (f for f in listdir(data_dir) if search_filename(f) is not None and int(search_filename(f).group(1)) > 3708) for filename in file_list: print(filename) search_stock_code = re.search('(\w+).csv$', filename) stock_code = search_stock_code.group(1) stock_codes = [stock_code] retriever.put_mapping_by_stock_codes() retriever.dump_to_es()
def setUp(self): self.retriever = Retriever()
class TestRetriever(unittest.TestCase): def setUp(self): self.retriever = Retriever() def tearDown(self): self.retriever = None def test_get_filename_by_stock_code(self): stock_code = '0050' filename = self.retriever.get_filename_by_stock_code(stock_code) self.assertEqual(filename, "{}/{}.csv".format(Retriever.data_dir, '0050')) def test_readfiles_by_stock_codes(self): # xxxx.csv 不存在,要噴 Exception stock_codes = ['0050', 'xxxx'] with self.assertRaises(RetrieverException): data = self.retriever.readfiles_by_stock_codes(stock_codes) for stock_code, line_number, line in data: break # 檔案存在 stock_codes = ['1204', '1212'] # 1204, 1212 已下市不會再有新的資料 data = self.retriever.readfiles_by_stock_codes(stock_codes) stock_code = '' line_number = 0 line = '' for stock_code, line_number, line in data: continue self.assertEqual(stock_code, '1212') self.assertEqual(line_number, 329) self.assertEqual( line, '94/06/03,254000,53340,0.21,0.21,0.21,0.21,-0.01,9\n') def test_save_line(self): stock_code = 'xxxx' line_number = 1 line = 'test' self.retriever.save_line(stock_code, line_number, line) self.assertEqual(self.retriever.line_pool[stock_code][line_number], line) def test_check_has_previous_data(self): # 第 1 行前面沒資料 line_number = 1 previous_days = 1 check = self.retriever.check_has_previous_data(line_number, previous_days) self.assertFalse(check, msg="1st line should have no previous line") # 第 3 行前面有 2 筆資料 line_number = 3 previous_days = 2 check = self.retriever.check_has_previous_data(line_number, previous_days) self.assertTrue(check, msg="3rd line should have 2 previous lines") # 第 3 行前面沒有 3 筆資料 line_number = 3 previous_days = 3 check = self.retriever.check_has_previous_data(line_number, previous_days) self.assertFalse(check, msg="3rd line shouldn't have 3 previous lines") def test_get_line_by_number(self): stock_code = '1204' # 1204 已下市不會再有新的資料 line_number = 373 line = self.retriever.get_line_by_number(stock_code, line_number) self.assertRegexpMatches(line, '94/09/09,0,0,--,--,--,--,,0') def test_get_previous_valid_lines(self): # 1204 第 261 行是空的,應該要跳過取得 260 行 stock_code = '1204' line_number = 262 max_size = 1 lines = self.retriever.get_previous_valid_lines( stock_code, line_number, max_size) for line in lines: self.assertEqual( line, '94/02/23,25043,98216,3.96,3.98,3.90,3.97,-0.01,15') # 不足 max_size stock_code = '1204' line_number = 6 max_size = 10 lines = self.retriever.get_previous_valid_lines( stock_code, line_number, max_size) self.assertEqual(len(lines), 5) def test_get_next_valid_lines(self): # 1204 第 261 行是空的,應該要跳過取得 262 行 stock_code = '1204' line_number = 260 max_size = 1 lines = self.retriever.get_next_valid_lines(stock_code, line_number, max_size) for line in lines: self.assertEqual(line, '94/02/25,42010,167609,3.98,4.00,3.98,3.98,X,17') # 不足 max_size stock_code = '1204' line_number = 371 max_size = 10 lines = self.retriever.get_next_valid_lines(stock_code, line_number, max_size) self.assertEqual(len(lines), 1) def test_get_previous_valid_closing_price(self): # 沒有之前的資料 stock_code = '1204' line_number = 1 with self.assertRaises(RetrieverException) as cm: self.retriever.get_previous_valid_closing_price( stock_code, line_number) the_exception = cm.exception self.assertEqual(str(the_exception), 'no previous line') def test_get_difference(self): # 沒有之前的資料 stock_code = '1204' line_number = 1 difference = self.retriever.get_difference(stock_code, line_number) self.assertIsNone(difference) # 有前一個交易日的資料 stock_code = '1204' line_number = 2 difference = self.retriever.get_difference(stock_code, line_number) self.assertEqual(difference, -0.50) # 前一個交易日暫停交易,抓前一個有效交易日的資料 stock_code = '1204' line_number = 262 difference = self.retriever.get_difference(stock_code, line_number) self.assertEqual(difference, 0.01) # 這個交易日暫停交易 stock_code = '1204' line_number = 261 difference = self.retriever.get_difference(stock_code, line_number) self.assertIsNone(difference) def test_get_change_percent(self): # 沒有之前的資料 stock_code = '1204' line_number = 1 change_percent = self.retriever.get_change_percent( stock_code, line_number) self.assertIsNone(change_percent) # 前一個交易日收盤價是 0 stock_code = '2326' line_number = 47 change_percent = self.retriever.get_change_percent( stock_code, line_number) self.assertIsNone(change_percent) # 有前一個交易日的資料 stock_code = '1204' line_number = 2 change_percent = self.retriever.get_change_percent( stock_code, line_number) self.assertEqual(round(change_percent, 4), -0.0690) # 前一個交易日暫停交易,抓前一個有效交易日的資料 stock_code = '1204' line_number = 262 change_percent = self.retriever.get_change_percent( stock_code, line_number) self.assertEqual(round(change_percent, 4), 0.0025) # 這個交易日暫停交易 stock_code = '1204' line_number = 261 change_percent = self.retriever.get_change_percent( stock_code, line_number) self.assertIsNone(change_percent) def test_get_line_data_dict(self): line = '94/02/03,2000,8000,4.00,4.00,4.00,4.00,0.07,2\r\n' data_dict = self.retriever.get_line_data_dict(line) assert_dict = { 'date': '94/02/03', 'volume': '2000', 'turnover': '8000', 'opening_price': '4.00', 'highest_price': '4.00', 'lowest_price': '4.00', 'closing_price': '4.00', 'difference': '0.07', 'transactions': '2', } self.assertDictEqual(data_dict, assert_dict) def test_break_consolidation_area(self): # 不滿足預設參數條件 stock_code = '1204' line_number = 20 check = self.retriever.break_consolidation_area( stock_code, line_number) self.assertFalse(check) # 不滿足自訂參數條件 stock_code = '4102' line_number = 44 check = self.retriever.break_consolidation_area( stock_code, line_number, 10, 0.05) self.assertFalse(check) # 滿足預設參數條件 stock_code = '1204' line_number = 44 check = self.retriever.break_consolidation_area( stock_code, line_number) self.assertTrue(check) # 滿足自訂參數條件 stock_code = '1204' line_number = 216 check = self.retriever.break_consolidation_area( stock_code, line_number, 10, 0.09) self.assertTrue(check) def test_check_model_1(self): # 不滿足此條件的 stock_code = '1204' line_number = 20 check = self.retriever.check_model_1(stock_code, line_number) self.assertFalse(check) # 滿足此條件的 stock_code = '1204' line_number = 229 check = self.retriever.check_model_1(stock_code, line_number, min_price=4, min_volume=200 * 1000, max_volume=300 * 1000, consolidation_days=10) self.assertTrue(check) # 暫停交易的 stock_code = '1204' line_number = 261 with self.assertRaises(RetrieverException) as cm: check = self.retriever.check_model_1(stock_code, line_number) the_exception = cm.exception self.assertEqual(str(the_exception), 'no data') def test_search_line_by_date(self): stock_code = '1204' date = '94/09/09' line_number = self.retriever.search_line_number_by_date( stock_code, date) self.assertEqual(line_number, 373) def test_get_simulation_1_info(self): stock_code = '1204' date = '94/02/24' info = self.retriever.get_simulation_1_info(stock_code, date, 10) data_set = info['data_set'] return_rate = '' for date, price, return_rate in data_set: continue self.assertEqual(info['pick_date'], '94/02/24') self.assertEqual(info['buy_in_price'], 3.98) self.assertEqual(return_rate, -0.0628)
def simulate(stock_codes, pick_date_obj, max_days, stop_loss_factor): retriever = Retriever() total_cost = 0 total_revenue = 0 total_roi = 0 buy_in_unit = 1 # summary_set = [] stop_loss_count = 0 # 開始買進時間 start_date_obj = None start_date_tw = '' end_date_obj = None end_date_tw = '' max_through_days = 0 pick_date_tw = RocDateConverter().get_roc_date_by_datetime(pick_date_obj) for stock_code in stock_codes: info = retriever.get_simulation_1_info(stock_code, pick_date_tw, max_days, stop_loss_factor) spend = info['buy_in_price'] * 1000 * buy_in_unit buying_fee = max(spend * 0.001425 * 0.65, 20) cost = spend + buying_fee total_cost += cost # print('股票編號: {}'.format(stock_code)) data_set = info['data_set'] if len(data_set) < max_days: stop_loss_count += 1 closing_price = 0 for data in data_set: # print(data) date_tw = data[0] date_obj = RocDateConverter().get_datetime_in_roc(date_tw) if (start_date_obj is None) or (date_obj < start_date_obj): start_date_obj = date_obj start_date_tw = date_tw if (end_date_obj is None) or (date_obj > end_date_obj): end_date_obj = date_obj end_date_tw = date_tw closing_price = data[1] income = closing_price * 1000 * buy_in_unit selling_fee = max(income * 0.001425 * 0.65, 20) tax = income * 0.003 revenue = income - selling_fee - tax total_revenue += revenue timedelta = end_date_obj - start_date_obj through_days = timedelta.days + 1 if through_days > max_through_days: max_through_days = through_days # summary_set.append('股票編號: {}, 買進成本: {}, 賣出日期: {}, 賣出總價: {}'.format(stock_code, cost, end_date_tw, revenue)) # summary = '\n'.join(summary_set) total_roi = (total_revenue - total_cost) / total_cost formatted_roi = '{}%'.format(round(total_roi * 100, 2)) formatted_cost = '{:,.0f}'.format(total_cost) net = total_revenue - total_cost formatted_net = '{:,.0f}'.format(net) pick_date = pick_date_obj.strftime("%Y/%m/%d") print('選股日期 {}, 開始日期 {}, 結束日期 {}, 停損 {}/{}' .format(pick_date, start_date_tw, end_date_tw, stop_loss_count, len(stock_codes))) # print(summary) print('總成本: {}, 利潤: {}, 投報率: {}\n' .format(formatted_cost, formatted_net, formatted_roi)) result = { 'roi': total_roi, 'cost': total_cost, 'net': net, 'days': max_through_days, 'formatted_data_dict': { 'pick_date': pick_date, 'start_date_tw': start_date_tw, 'end_date_tw': end_date_tw, 'pick_count': len(stock_codes), 'stop_loss_count': stop_loss_count, 'cost': formatted_cost, 'net': formatted_net, 'roi': formatted_roi, } } return result
def test_one(stock_code, date): retriever = Retriever() line_number = retriever.search_line_number_by_date(stock_code, date) check = retriever.check_model_1(stock_code, line_number) print(check)
#!/usr/bin/python # -*- coding: utf-8 -*- import sys from classes.retriever import Retriever stock_codes = ['1204'] retriever = Retriever() read = retriever.readfiles_by_stock_codes(stock_codes) for stock_code, line_number, line in read: check = retriever.check_condition_1(stock_code, line_number) if check: print(line_number, check)