Tuesday 13 February 2018

거래 시스템 데이터베이스 스키마


거래 시스템 데이터베이스 스키마
App Store를 통해 가져 오기 우리의 응용 프로그램 에서이 게시물을 읽으십시오!
과거 주가 데이터 구성을위한 데이터베이스 스키마.
과거의 주식 데이터를 저장하기위한 데이터베이스 스키마를 만들고 있습니다. 나는 현재 아래와 같은 스키마를 가지고있다.
내 요구 사항은 여러 주식 기호에 대해 "바 데이터"(날짜, 공개, 고가, 저가, 가까운 볼륨)를 저장하는 것입니다. 각 기호에는 Google 주간 막대 및 Google 일일 막대와 같이 여러 시간대가있을 수도 있습니다.
현재 스키마는 OHLCV 테이블에 대량의 데이터를 넣습니다. 나는 데이터베이스 전문가와는 거리가 멀고 너무 순진한 지 궁금하다. 건설적인 입력을 환영합니다.
이것은 내 쿼리가 현재 다음과 같은 것을 의미합니다. 지정된 심볼 / 시간 프레임에 대한 timeframeID를 찾은 다음 timeframeID가 일치하는 OHLCV 테이블에서 선택을 수행합니다.
음, 긍정적 인 측면에서, 먼저 입력을 요청하는 것이 좋습니다. 따라서 데이터베이스 디자인에 익숙하지 않은 사용자의 90 % 이상을 앞서게됩니다.
명확한 외래 키 관계는 없습니다. 시간이 걸릴 것입니다. ID는 symbolID와 관련이 있습니까? 당신이 어떻게 이런 식으로 찾을 수 있을지는 불분명합니다. 위에 언급 한 외래 키를 읽으면 약간의 노력으로 엄청난 이해력을 향상시킬 수 있습니다. 시간 프레임 데이터를 TEXT로 저장하고 있습니다. 유용성 측면 에서뿐만 아니라 성과면에서도 그렇습니다. 귀하의 현재 구성표는 주식 분할을 수용 할 수 없으며 결국 분할됩니다. 가격 데이터 테이블과 Symbol open, high, low, close prices 사이에 하나의 추가 간접 계층을 추가하는 것이 10 진수 또는 통화 유형으로 저장하는 것이 더 좋으며, 바람직하게는 제수를 저장하는 별도의 INTEGER 필드가있는 INTEGER 필드로 저장하는 것이 좋습니다 허용되는 최소 가격 비율 (센트, 달러 등)은 교환마다 다릅니다. 여러 교환을 지원하므로 여러 통화를 지원해야합니다.
이 모든 것이 너무 '건설적인'것처럼 보이지 않는다면 사과드립니다. 특히 지금은 좀 더 쓸모있는 대안을 제안하기에는 너무 졸려서. 나는 위가 당신을 당신의 길로 인도 할 수 있기를 바랍니다.
우리는 오랫동안 많은 양의 데이터를 저장하기위한 적절한 데이터베이스 구조를 찾으려고 노력했습니다. 아래의 솔루션은 6 년 이상의 경험으로 얻은 결과입니다. 이제 양적 분석을 위해 완벽하게 작동합니다.
우리는 SQL Server에서이 구성표를 사용하여 수백 기가 바이트의 일중 및 일별 데이터를 저장할 수있었습니다.
모든 거래 수단은 하나의 테이블에 저장됩니다. 또한 기호, 날짜 및 시간 열에 클러스터 된 인덱스가 있습니다.
일일 데이터의 경우 별도의 표가 있으며 시간 열을 사용하지 않습니다. 볼륨 데이터 유형은 또한 int 대신 bigint입니다.
성능? 우리는 밀리 초 만에 서버에서 데이터를 가져올 수 있습니다. 데이터베이스 크기는 거의 1 테라 바이트임을 기억하십시오.
우리는 Kibot 웹 사이트에서 모든 역사적인 시장 데이터를 구입했습니다 : kibot /
Timeframe에서 어떤 값을 더하는 지 불확실합니다. 불필요한 복잡성처럼 보이지만, 이해가 안되는 것일 수 있습니다 ;-) Timeframe에 OHLCV가 하나 이상 있습니까? 그렇지 않다면 나는 병합을 제안한다.
주식 시세 표시기는 여러 가지 이유로 때때로 변경됩니다. 빈번한 이벤트는 아니지만 일어납니다. 데이터를 시계열로 사용할 생각이라면 문제가 발생했을 때이를 처리 할 수 ​​있도록 이전에 없었던 문제를 인식해야합니다. 주식을 추적하고 있지 않다면 (미래 선물에 종사하고있을 수도 있습니다),이 조언은 적절한 양의 소금과 함께 취할 수 있습니다.
다시금 주가와 관련이 있으며 분할은 다른 곳에서 언급되었으며 배당금을 고려할 수도 있습니다. 주식 가격은 일반적으로 배당금 전의 배당금 (또는 현재의 현재 가치)으로 떨어지게됩니다. 당신은 확인 된 미래의 현금 흐름을 알지 못합니다 이유입니다. 권리 문제도 재미있을 수 있습니다.
특정 심볼에 대한 일련의 데이터를 살펴볼 계획이라면 어떤 종류의 성능을 얻는 지 살펴보아야합니다. 최소한 적절한 색인이 있는지 확인하십시오.

게임 및 플레이어.
가장 일반적인 통계 중 하나가 표시되기를 원한다고 생각합니다. "플레이어 X에 대한 내 통계는 무엇입니까?" 이러한 쿼리의 경우 game_master 테이블은 실제로 최적화되어 있지 않습니다.
"사용자 ID 6354가 재생 한 모든 game_ids 찾기"에 대한 쿼리를 만들고 싶다고 가정 해 봅시다.
어어! 대개 사용자 ID와 사용자 이름 만 갖고 있지 않다는 것을 고려하면 플레이어 테이블에 참여하려면 여기에 두 개의 조인을해야합니다.
게임과 플레이어간에 많은 관계를 갖는 것이 더 낫습니다. 한 사람은 많은 게임에서 게임을 할 수 있고 한 게임에는 여러 플레이어를 포함 할 수 있습니다. 한 게임에 두 명의 플레이어 만 포함된다는 사실 (적어도 현재는)은 부적합합니다. 하나 일 수도 있고 많을 수도 있습니다.
이 관계에 대한 games_players 테이블을 만듭니다. 여기에는 game_id, player_id, result가 포함될 수 있습니다. 결과는 미래에 어떤 수의 선수라도 지원할 수있는 정수가 될 수 있습니다. 결과 = 1, 승자는 2, 결과는 2 (2 위), 결과는 8 (8 명 게임 등)에서 "가장 큰 패자"
이제이 쿼리를 다시 작성해 보겠습니다.
아, 훨씬 나아! 지나치게 많은 노력을 기울이지 않아도 동일한 쿼리에서 승패의 수를 찾기 위해 확장 될 수 있습니다. 또한 플레이어 테이블에 쉽게 가입하여 특정 플레이어 이름에 대한 플레이어 ID를 확인할 수 있습니다.
게임 동작.
"End Turn"자체에 액션이 있다고 생각한다면, 이 "턴"정수는 실제로 필요하지 않습니다.
음. 공격 외에는 가능한 다른 행동이있을 것이라고 확신합니다. 맞습니까? 그리고이 칼럼의 정확한 목적은 무엇입니까? 얼마나 많은 공격 피해가 처리 되었습니까? 그것은 매우 혼란스러운 이름이고 나는 당신이 그것을 사용해야 하는지를 스스로 알지 못합니다.
어디에도 "action_id"또는 "action_name"이 표시되지 않습니다. 한 카드에 여러 개의 가능한 작업이있는 경우 action_id 열이 필요합니다.
액션 타겟.
둘 이상의 카드를 타겟팅 할 수있는 액션은 무엇입니까? 여러 다른 "targetSets"에서 둘 이상의 카드를 타겟팅 할 수있는 작업은 어떻게됩니까? 예를 들어 Magic : The Gathering 카드를 생각해보십시오 Sun God을 엿볼 수 있습니다 :
X 타겟 생물을 탭합니다. Scry 1. (도서관의 최상위 카드를보십시오. 도서관의 하단에 그 카드를 놓을 수 있습니다.)
이 행동에 대해 무엇을 저장해야합니까? 우리는 연주 된 카드가 "일별 엿보기"라는 것을 알고 있으며, 카드 ID, 플레이어 ID, 액션 ID를 가지고 있습니다. 이제 "X"에 대한 값을 저장해야하며 실제 생물 표적을 저장해야하며 도서관 맨 위에있는 카드가 라이브러리 맨 아래에 놓 였는지 여부를 저장해야합니다.
Gods Willing과 같은 다른 카드는 선택한 색상에 대한 정보를 저장해야합니다. 그러면 Scry의 인스턴스가 여러 개있는 Cryptic Annelid와 같은 카드가 있습니다. 어떤 카드가 각 Scry에서 도서관의 바닥에 놓였습니까? 카드를 맨 위에 놓은 순서는?
이제 Magic : The Gathering을 지원하기를 원하지 않을 수도 있습니다. 그러나 만약 당신이 그렇게하거나, 그런 게임을 지원하고 싶거나 단순히 하나 이상의 목표를 가질 수있는 행동을 지원하기를 원한다면 (플레이어가 아마도 전환해야하는 개별 카드를 선택할 수있는 게임의 시작에서 어떤 종류의 멀리 건이 있습니까?) 단순히 target_player 및 target_card 만 있으면 충분하지 않습니다.
target_player 및 target_card라고 말하면 그들을 분리하지 마십시오. 게임 내에서 플레이어에게 ID를주고 카드에 ID를 부여하고 물론 ID에 충돌이 없는지 확인한 다음 대상 ID를 저장하면됩니다.
데이터베이스에이 'mod'테이블이 있는데, 이것이 의미하는 바가별로 설명되어 있지 않습니다. 이것은 데이터베이스가 여러 종류의 게임에 사용될 수 있어야한다는 것을 의미한다고 가정합니다. 그렇다면 카드 표를 살펴 보겠습니다.
모든 개조자는 그 값을 사용합니까? 더 복잡한 마나 비용을 사용하는 Magic : The Gathering-style Mod는 어떨까요? 무색 마나 3 장, 파란색 1 장, 흰색 1 장, 녹색 마나 1 장, 마나 비용 X를 저장하는 방법은 무엇입니까? 사물을 악화 시키려면 사신 왕이 무색 마나 또는 유색 마나를 지불 할 수 있습니까?
결론.
트레이딩 카드 게임은 까다로운 사업입니다. 데이터베이스에서 실제 게임 로직을 수행하지 않기를 진심으로 바라고 (Card X 공격 Y에 대한 저장 프로 시저가없고 카드 X가 죽는 데 3 가지 피해를줍니다.), 데이터베이스의 세부 수준을 제한하고자 할 수 있습니다. 저장. 고급 작업에 대한 대상 지정의 복잡성을 감안할 때 모든 대상에 대한 정보를 직렬화 가능 형식으로 저장하십시오. 예를 들어, 태양의 신을 엿볼 수 있다고 가정 해 봅시다.
X 타겟 생물을 탭합니다. Scry 1. (도서관의 최상위 카드를보십시오. 도서관의 하단에 그 카드를 놓을 수 있습니다.)
X의 값을 extra_data 열에 저장합니다. 이 값은 원하는 작업에 대해 선택한 색상을 포함 할 수 있으므로 텍스트 여야합니다. 그런 다음 표적 생물이 41, 42, 43이라고 가정 해 봅시다. 그리고 그 결과는 도서관의 바닥에 두는 것이 었습니다. 이 정보를 저장하기 위해 다음과 같이 serialize 할 수 있습니다 : 41,42,43; BOTTOM 또는 41,42,43; (63이 라이브러리 맨 아래에 놓을 수있는 선택된 카드이고 마지막에 세미콜론 다음에 빈 문자열로 표시된 카드가 맨 위에 놓이지 않았 음을 나타냄).
이제 SELECT * FROM game_actions WHERE target_card = 42; 더 이상, 하지만 전에도 그렇게 해? 그 모든 상황을 알지 못하고 게임 로직이 근처에 없으면 무엇을 드릴까요? JDBC가 관련되어 있다고 말하는 것처럼, 자바쪽에 더 넣는 편이 나을 것 같다. JDBC가 데이터베이스에서 수행 된 모든 조치에 대한 정보를 가져오고 실제 게임 이벤트를 재생할 수 있으면 Java는 대상 42가 포함 된 조치를 필터링하고 검색 할 수 있습니다.
다시 말하지만 데이터베이스에 높은 수준의 세부 정보를 저장하지 않을 수 있습니다. 모든 카드에 scrap_value가있는 것은 아닙니다. 이러한 '값'을 직렬화 가능한 형식으로 저장하고 SELECT * FROM 카드 대신 scrap_value = 5를 사용하는 대신 응용 프로그램 코드가 해당 코드를 검색하고 역 직렬화하고 특정 카드를 필터링하도록 할 수 있습니다. 성능에 영향을 미치지 만 유연성을 향상시킵니다. 또 다른 대안은 이러한 값에 대해 card_values ​​many-to-many 관계를 사용하는 것입니다. 이 특별한 경우, 다 대 다 관계를 사용하는 몇 가지 이유를 볼 수 있지만, 이것이 최선의 선택이라고 완전히 확신하지는 못합니다.
나는 정말로 여기서 논평 할 것이별로 없다. 코드는 읽기 쉽고 구조가 잘되었으며 코드 스타일은 SQL의 경우 눈이 비교적 쉬우 며 일관성이있어 좋았습니다.
내가보기에 하나의 모순점은 다음과 같습니다.
그러나 스키마의 이미지는 last_seen_date가 시간대없이 생성되었음을 명확하게 보여줍니다. 내가 조사했을 때, 나는 발견했다.
주 : SQL 표준에서는 타임 스탬프를 쓰지 않고 시간대가없는 타임 스탬프와 동일해야하며 PostgreSQL은 해당 동작을 인식합니다.
따라서, WITHOUT TIME ZONE을 지정하지 않아도됩니다. 그렇지 않으면 일관되게 수행해야합니다.
모든 테이블의 create_date (또는 start_date)는 NOW ()로 기본값 설정되지만 열은 여전히 ​​null입니다. CreateDate는 결코 null이 아니며 NOT NULL로 만들어야합니다.
나는 카드에있는 타입 칼럼에 대해 의심 스럽다. 이와 같은 열은 일반적으로 작은 도메인입니다 (몇 개의 값만 있고 여러 번 반복됩니다). 그것은 cardtype 테이블로 정규화되어야하고, type 컬럼은 type_id로 대체됩니다. 이렇게하면 잠재적으로 시스템의 성능과 유지 보수성이 향상됩니다. 물론, 타입에 반복이 거의없는 다양한 값이있는 경우 정규화가 의미가 없습니다.
마찬가지로, 나는 갑판에 버전 열의 sispicious입니다. 이 값은 사용자가 제시 한 내용을 토대로 명확한 의미를 갖지 않는 응용 프로그램과 관련된 값입니다. 나는 그것이 무엇을 위해 사용될 것인지 짐작할 수 있지만 나머지 스키마는 명확하기 때문에 존재하는 것으로 두드러진다. '무딘'.
Fnally, 나는 당신이 몇몇 색인을 놓치기를 기대합니다.
Postgres는 기본 및 외래 키 열을 인덱싱하지만 player. name, mod. name 및 card. name의 인덱스는 좋을 것이라고 생각합니다 (mod 및 카드 이름을 고유하게 만드는 것이 좋습니다).
rolfl과 SimonAndréForsberg가 제안한 거의 모든 것을 적용하고 스키마를 매우 단순화했습니다. 원래 game_action에 액션을 저장하려고 계획했지만 Java 서버가 이미이 모든 것을 저장하고 있기 때문에 중요한 점은별로 없습니다.

QuantStart.
빠르게 성장하는 소매점 퀀텀 트레이더 커뮤니티를 지원하는 Quantcademy 개인 회원 포털에 가입하십시오. 당신은 당신의 가장 중요한 퀀트 트레이딩 질문에 대답 할 준비가되어있는 지식이 풍부하고 마음이 맞는 퀀트 트레이더 그룹을 찾을 수 있습니다.
퀀트 트레이딩에 관한 나의 eBook을 확인해보십시오. 여기서 저는 파이썬 툴로 수익성 높은 체계적인 트레이딩 전략을 만드는 법을 가르쳐드립니다.
Python 및 R을 사용하여 시계열 분석, 기계 학습 및 베이지안 통계를 사용하는 고급 거래 전략에 관한 새로운 전자 책을 살펴보십시오.
Michael Halls-Moore (2013 년 5 월 17 일)
알고리즘 거래에서 스포트 라이트는 대개 전체 거래 시스템의 알파 모델 구성 요소에서 빛납니다. 이것은 위험 관리 또는 포트폴리오 구축 시스템에 의해 필터링되기 전에 거래 신호를 생성하는 시스템의 일부입니다. 따라서 알 고어 거래자는 자신의 시스템을 생산에 투입하기 전에 가장 큰 백 테스트 된 Sharpe 비율을 생성하기 위해 알파 모델을 정제하는 데 많은 시간을 소비합니다.
그러나 알파 모델은 공급되는 데이터만큼이나 우수합니다. 이 개념은 "쓰레기통, 쓰레기통"이라는 오래된 컴퓨터 과학에 의해 잘 요약됩니다. 정확하고시의 적절한 데이터가 알파 모델을 공급하는 데 사용되는 것이 중요합니다. 그렇지 않으면 결과가 좋지 않거나 최악의 경우 완전히 잘못되어 시스템을 생산에 투입하면 큰 손실을 초래할 수 있습니다.
이 기사에서는 알고리즘 전략 백 테스팅 시스템 및 궁극적으로 거래 실행 엔진을위한시기 적절한 데이터의 수집 및 제공과 관련된 문제에 대해 논의하고자합니다. 특히 재무 데이터를 얻는 방법, 저장 방법, 정리 방법 및 수출 방법을 연구 할 것입니다. 금융 산업에서 이러한 유형의 데이터 서비스는 증권 마스터 데이터베이스로 알려져 있습니다.
증권 마스터 란 무엇입니까?
증권 마스터는 자산 클래스 전반에서 다양한 금융 상품에 대한 기본, 가격 및 거래 데이터를 저장하는 조직 전체의 데이터베이스입니다. 리스크 관리, 청산 / 결제 및 독점 거래와 같이 다른 부서에서 사용할 수 있도록 일관된 방식으로이 정보에 대한 액세스를 제공합니다.
대규모 조직에서는 다양한 도구와 데이터가 저장됩니다. 다음은 회사에 관심을 가질만한 도구들입니다 :
주식 지분 옵션 지표 외환 이자율 선물 상품 채권 - 정부 및 기업 파생 상품 - 대문자, 플로어, 스왑.
증권 마스터 데이터베이스는 종종 금융 기관 내에서 높은 가용성을 보장하는 개발자 및 데이터 전문가 팀을 보유합니다. 이것은 대기업, 소매 수준 또는 소액 기금에서 필요하지만 증권 마스터는 훨씬 간단 할 수 있습니다. 실제로 대형 유가공 마스터는 값 비싼 엔터프라이즈 데이터베이스 및 분석 시스템을 사용하지만 잘 최적화 된 시스템을 가정 할 때 동일한 수준의 기능을 제공하기 위해 범용 오픈 소스 소프트웨어를 사용할 수도 있습니다.
어떤 데이터 세트가 사용됩니까?
소매 알고리즘 거래자 또는 소량 계량 펀드의 경우 가장 일반적인 데이터 세트는 주식, 지수, 선물 (주로 상품 또는 채권) 및 외환 (외환)에 대한 일별 및 일 중 역사적 가격 책정입니다. 이 논의를 단순화하기 위해 주식, ETF 및 주식 지수에 대한 EOD (end-of-day) 데이터에만 집중할 것입니다. 최신 기사에서는 고급 요구 사항이있는 더 높은 빈도의 데이터, 추가 자산 클래스 및 파생 데이터를 추가하는 방법에 대해 설명합니다.
주식에 대한 EOD 데이터는 쉽게 구할 수 있습니다. 웹에서 사용 가능한 API를 통해 무료로 액세스를 제공하는 여러 가지 서비스가 있습니다.
개인 유가 증권에 대한 과거 데이터를 수동으로 다운로드하는 것은 간단하지만 많은 주식을 매일 다운로드해야하는 경우 시간이 많이 소요됩니다. 따라서 증권 마스터의 중요한 구성 요소는 데이터 세트를 자동으로 업데이트합니다.
또 다른 문제는 되돌아보기 기간입니다. 과거에는 데이터와 함께 얼마나 멀리 갈 필요가 있습니까? 이것은 거래 전략의 요구 사항에 따라 다르지만 모든 전략에 걸쳐있는 특정 문제가 있습니다. 가장 보편적 인 것은 새로운 규제 환경, 변동성이 더 높은 / 더 낮은 기간 또는 장기적인 동향 시장에 의해 종종 특징 지워지는 체제 변화이다. 예를 들어 2000-2003 년이나 2007-2009 년 사이에 장기간 단기 추세 추종 / 추세 전략이 잘 수행 될 것입니다. 그러나 그것은 2003-2007 년에서 현재까지 힘든 시간을 보냈습니다.
내 경험에 비추어 볼 때, 특히 스토리지가 저렴한 EOD 데이터의 경우 가능한 한 많은 데이터를 확보해야합니다. 보안 마스터에 데이터가 존재한다고해서 반드시 사용해야한다는 의미는 아닙니다. 데이터베이스 테이블이 클수록 쿼리 시간이 길어 지므로 (아래 참조) 성능면에서주의해야 할 사항이 있지만 샘플 지점을 늘리면 얻을 수있는 이점은 일반적으로 성능 문제를 능가합니다.
모든 금융 데이터에서와 마찬가지로 잘못된 고가 / 저가 또는 생존자 편향과 같은 오류를 알아야합니다. QuantStart (여기 참조)에서 자세히 논의했습니다.
데이터를 저장하는 데 사용되는 것은 무엇입니까?
재무 데이터를 저장하는 세 가지 주요 방법이 있습니다. 그들은 모두 다양한 수준의 액세스, 성능 및 구조적 기능을 갖추고 있습니다. 우리는 차례로 각각을 고려할 것입니다.
플랫 파일 저장소.
재무 데이터를위한 가장 간단한 데이터 저장소 및 데이터 공급 업체로부터 데이터를받을 가능성이있는 방식은 플랫 파일 형식입니다. 플랫 파일은 종종 쉼표로 구분 된 변수 (CSV) 형식을 사용합니다. 이 형식은 데이터의 2 차원 행렬을 일련의 행으로 저장하며 열 데이터는 구분 기호 (대개 쉼표이지만 공백 일 수 있습니다. 스페이스 또는 탭으로). EOD 가격 데이터의 경우 각 행은 OHLC 패러다임 (즉, 거래 기간의 공개, 고가, 저가 및 마감시 가격)을 통해 거래일을 나타냅니다.
플랫 파일의 장점은 단순성과 아카이브 또는 다운로드를 위해 크게 압축 할 수 있다는 것입니다. 주요 단점은 쿼리 기능이 부족하고 대규모 데이터 세트에서 반복되는 성능이 낮다는 것입니다. SQLite와 Excel은 특정 쿼리 기능을 제공하여 이러한 문제를 완화합니다.
Document Stores / NoSQL.
문서 저장소 / NoSQL 데이터베이스는 확실히 새로운 개념은 아니지만 최근 몇 년 동안 Google, Facebook 및 Twitter와 같은 "웹 규모"회사에서 사용되어 중요한 주목을 받았습니다. 테이블 스키마의 개념이 없다는 점에서 RDBMS 시스템과 상당히 다릅니다. 대신 컬렉션과 문서가 있으며, 각각 테이블과 레코드와 가장 유사합니다. 문서 저장소에 대한 폭 넓은 분류가 존재합니다. 이 문서는이 기사의 외부에 있습니다. 그러나 인기있는 상점에는 MongoDB, Cassandra 및 CouchDB가 있습니다.
재무 애플리케이션의 문서 저장소는 기본적으로 기본 데이터 또는 메타 데이터에 적합합니다. 금융 자산의 기본 데이터는 기업 활동, 손익 계산서, SEC 신고 등 다양한 형태로 제공됩니다. 따라서 스키마가없는 NoSQL DB의 특성이 적합합니다. 그러나 NoSQL DB는 고해상도 가격 데이터와 같은 시계열에 적합하지 않으므로이 기사에서 더 이상 고려하지 않을 것입니다.
관계형 데이터베이스 관리 시스템.
관계형 데이터베이스 관리 시스템 (RDBMS)은 관계형 모델을 사용하여 데이터를 저장합니다. 이러한 데이터베이스는 서로 다른 "개체"(예 : 교환, 데이터 원본, 가격)를 테이블간에 정의 된 관계로 분리 할 수 ​​있으므로 재무 데이터에 특히 적합합니다.
RDBMS는 재무 데이터에 대해 복잡한 데이터 쿼리를 수행하기 위해 SQL (Structured Query Language)을 사용합니다. RDBMS의 예로는 Oracle, MySQL, SQLServer 및 PostgreSQL이 있습니다.
RDBMS의 주요 이점은 설치가 간단하고 플랫폼 독립성이 뛰어나며 쿼리가 쉽고 주요 백 테스팅 소프트웨어와의 통합이 용이하며 대규모 기능을 갖춘 고성능 기능입니다 (일부는 그렇지 않다고 주장하지만). 이러한 단점은 종종 RDBMS 데이터가 저장되는 방법에 대한 기본 지식없이 사용자 정의의 복잡성과 성능의 어려움 때문에 발생합니다. 또한, 이들은 semi-rigid 스키마를 보유하고 있으므로 데이터는 종종 그러한 디자인에 맞게 수정되어야합니다. 이것은 NoSQL 데이터 저장소와 달리 스키마가 없습니다.
QuantStart에 대한 향후 히스토리 프라이싱 구현에 관한 모든 기사는 MySQL RDBMS를 사용합니다. 자유롭고, 오픈 소스이며, 플랫폼 간, 매우 견고하며 규모에 따른 행동이 잘 문서화되어있어 콴텔의 합리적인 선택이 가능합니다.
과거 데이터는 어떻게 구조화되어 있습니까?
데이터 저장소를위한 최적의 설계를 위해 컴퓨터 과학 영역에서 수행 된 많은 이론 및 학술 연구가 있습니다. 그러나, 우리는 세부 사항에서 길을 잃기 쉽기 때문에 너무 자세하게 설명하지 않을 것입니다! 대신 주식 보안 마스터 구축을위한 공통 패턴을 제시 할 것이며 이는 자신의 애플리케이션에 맞게 수정할 수 있습니다.
첫 번째 작업은 데이터베이스의 테이블에 결국 매핑되는 재무 데이터의 요소 인 엔터티를 정의하는 것입니다. 주식 마스터 데이터베이스의 경우 다음 엔티티를 예측합니다.
교환 - 데이터의 궁극적 인 원천은 무엇입니까? 공급 업체 - 특정 데이터 포인트는 어디서 얻을 수 있습니까? Instrument / Ticker - 주식 또는 지수의 시세 / 기호와 기본 회사 또는 펀드의 기업 정보. 가격 - 특정 날짜의 특정 보안에 대한 실제 가격입니다. 기업 활동 - 가격 데이터 조정에 필요한 모든 주식 분할 또는 배당 조정 목록 (하나 이상의 테이블로 이어질 수 있음). 국경일 - 거래 휴일을 데이터 오류 누락으로 잘못 분류하는 것을 피하려면 국경일과 상호 참조를 저장하는 것이 유용 할 수 있습니다.
표준 시세 표시기를 저장하는 것과 관련하여 중요한 문제가 있습니다. 나는이 정확한 문제를 다루는 헤지 펀드에서 직접 경험 한 것을 증명할 수 있습니다! 서로 다른 공급 업체는 시세를 해결하고 정확성을 위해 여러 소스를 결합하는 데 다른 방법을 사용합니다. 또한 기업은 파산하거나 M & A 활동에 노출되어 (즉, 인수 및 이름 / 기호 변경) 공개적으로 거래되는 주식 클래스가 여러 개있을 수 있습니다. 시세 대상이 S & P500 또는 FTSE350과 같은 대형 지수 구성 요소로 제한 될 것이기 때문에 많은 사람들이 걱정할 필요가 없습니다.
데이터의 정확성은 어떻게 평가됩니까?
공급 업체의 과거 가격 데이터에는 다양한 오류가 발생하기 쉽습니다.
기업 활동 - 주식 분할 및 배당 조정의 잘못된 처리. 수식이 올바르게 구현되었는지 절대적으로 확신해야합니다. 스파이크 - 특정 과거 변동성 수준을 크게 초과하는 가격 결정 포인트. 이 스파이크가 발생하면 여기에서주의해야합니다 - 무서운 예제로 May Flash Crash를보십시오. 스파이크는 주식 분할이 발생할 경우이를 고려하지 않아도 발생할 수 있습니다. 스파이크 필터 스크립트는 이러한 상황을 거래자에게 알리는 데 사용됩니다. OHLC 집계 - Yahoo / Google과 같은 무료 OHLC 데이터는 소규모 거래가 낮의 '주요'교환 가격보다 큰 소규모 거래를 처리하는 '불량 틱 집계'상황에 특히 취약하여 최대 초과 / 최대치를 초래합니다 한번 집계. 이것은 '오류'는 적지 만주의해야 할 문제가 많습니다. 누락 된 데이터 - 누락 된 데이터는 특정 기간 (일반적으로 비유동 소형 대문자의 초 / 분 해상도 데이터에서의 거래 부족), 거래 휴일 또는 교환 시스템의 오류로 인해 발생할 수 있습니다. 누락 된 데이터는 거래 시스템에 따라 패딩 (즉, 이전 값으로 채워짐)되거나 보간 (선형 또는 기타)되거나 무시 될 수 있습니다.
이러한 오류의 대부분은 진행 방법을 결정하기 위해 수동 판단에 의존합니다. 이러한 오류에 대한 알림을 자동화하는 것은 가능하지만 솔루션을 자동화하는 것이 훨씬 어렵습니다. 예를 들어 스파이크에 대해 말하기위한 기준점을 선택해야합니다. 표준 편차는 몇 회 사용하고 되돌아 오는 기간에는 얼마입니까? stdev가 너무 높으면 스파이크가 빠질 수 있지만 너무 낮거나 비정상적인 뉴스가 많이 나타나는 경우 오탐 (false positive)이 발생합니다. 이러한 모든 문제는 퀀트 트레이더의 진보 된 판단을 필요로합니다.
또한 오류를 수정하는 방법을 결정할 필요가 있습니다. 오류가 알려지 자마자 수정해야합니까? 그렇다면 감사 추적을 실시해야합니까? DB에 여분의 테이블이 필요합니다. 이것은 우리에게 back-filling에 관한 주제로 데려옵니다. 이것은 backtesting을 위해 특히 교활한 문제입니다. 업스트림의 잘못된 데이터를 자동으로 수정하는 것과 관련이 있습니다. 데이터 공급 업체에서 이전 오류를 수정했지만 이전에 불량 데이터를 조사한 결과를 바탕으로 백 테스팅 된 거래 전략이 생산 단계에있는 경우 전략의 효율성에 대한 결정을 내릴 필요가 있습니다. 이것은 전략 성과 지표 (특히 각 거래의 승패 특성의 차이)를 완전히 인식함으로써 어느 정도 완화 될 수 있습니다. 단일 데이터 요소가 전략의 성능을 크게 왜곡 할 수 없도록 전략을 선택하거나 설계해야합니다.
이러한 프로세스는 어떻게 자동화됩니까?
데이터의 다운로드, 저장 및 정리를 수행하기위한 소프트웨어 스크립트 작성의 이점은 운영 체제가 제공하는 도구를 통해 스크립트를 자동화 할 수 있다는 것입니다. UNIX 기반 시스템 (예 : Mac OSX 또는 Linux)에서는 crontab을 사용할 수 있습니다. crontab은 사용자 정의 된 시간 또는 정기적 인 기간에 특정 스크립트를 실행할 수 있도록하는 연속 실행 프로세스입니다. MS Windows에는 작업 스케줄러라는 동일한 프로세스가 있습니다.
예를 들어, 생산 프로세스를 통해 데이터 공급 업체를 통해 게시되는 즉시 S & P500 최종 가격을 모두 자동으로 다운로드 할 수 있습니다. 그런 다음 위에서 언급 한 누락 된 데이터 및 스파이크 필터링 스크립트를 자동으로 실행하여 상인, SMS 또는 기타 알림 형식으로 경고합니다. 이 시점에서 모든 백 테스트 도구는 상인이 손가락을 들어야하지 않고도 최신 데이터에 자동으로 액세스 할 수 있습니다! 거래 시스템이 데스크탑에 있는지 또는 원격 서버에 있는지에 따라 이러한 작업을 위해 반자동 또는 완전 자동 프로세스를 선택할 수도 있습니다.
외부 소프트웨어에 제공된 데이터는 어떻게됩니까?
데이터가 자동으로 업데이트되어 RDBMS에 저장되면 백 테스팅 소프트웨어로 가져와야합니다. 이 프로세스는 데이터베이스 설치 방법 및 거래 시스템이 로컬 (예 : 데스크톱 컴퓨터)인지 원격 (예 : 공동 위치의 교환 서버)인지에 따라 크게 달라질 수 있습니다.
가장 중요한 고려 사항 중 하나는 과도한 입출력 (I / O)을 최소화하는 것입니다. 대역폭과 비용이 많이 드는 원격 연결을 가정하면 시간과 비용면에서 극도로 비싸기 때문입니다. 이 문제에 접근하는 가장 좋은 방법은 데이터를 선택 쿼리를 통해 필요로하거나 데이터를 내보내고 압축하는 네트워크 연결을 통해서만 데이터를 이동하는 것입니다.
많은 RDBMS가 복제 기술을 지원하므로 일반적으로 대기 시간이있는 다른 원격 시스템에 데이터베이스를 복제 할 수 있습니다. 설정 및 데이터 양에 따라이 시간은 분 또는 초 단위 일 수 있습니다. 간단한 방법은 원격 데이터베이스를 로컬 데스크톱에 복제하는 것입니다. 그러나 동기화 문제는 공통적이며 수정하는 데 시간이 많이 걸립니다.
아래에서 몇 가지 예시 상황을 시도해 보겠습니다. 그러나이 문제에 접근하는 방법은 다양하며 개별 설정에 매우 중요합니다.
MySQL을 사용한다면 Python과 같은 오픈 소스 스크립팅 언어 (MySQLdb 라이브러리 또는 SQLAlchemy ORM을 통해)를 사용하여 데이터베이스에 연결하고 쿼리를 실행할 수 있습니다.
pandas와 같은 최신 데이터 분석 라이브러리는 MySQL에 직접 액세스 할 수 있습니다 (예제에서는이 스레드 참조).
또한 선호하는 언어 / 환경 (C ++, C #, Matlab)과 ODBC 링크를 사용하여 MySQL 인스턴스에 연결할 수 있습니다.
MS SQLServer.
SQLServer는 LINQ ORM을 통해 C # 및 Visual Basic과 같은 MS 언어에 쉽게 연결되도록 설계되었습니다. pyODBC를 통해 Python으로 SQLServer에 연결할 수도 있습니다.
데이터 저장소와 백 테스트 환경에 대한 다른 많은 조합이 있습니다. 그러나이 설정에 대한 논의는 이후 기사에서 끝내겠습니다.
다음 단계.
향후 기사에서는 유가 증권 마스터의 구현에 대한 기술적 세부 사항을 논의 할 예정입니다. 특히 MySQL을 설치하고 가격 데이터를 구성하고 Yahoo / Google 재무에서 EOD 데이터를 얻고 팬더 데이터 분석 라이브러리를 통해 탐색합니다.
양적 거래 시작하기?
QuantStart 목록을 구독해야하는 3 가지 이유 :
1. 퀀트 트레이딩 레슨.
계량 거래를 시작하는 데 도움이되는 힌트와 팁으로 가득한 무료 10 일간 코스에 즉시 액세스 할 수 있습니다!
2. 모든 최신 내용.
매주 나는 퀀트 스타트에서 모든 활동의 포장을 보내드릴 것입니다. 그래서 당신은 결코 다시 글을 놓치지 않을 것입니다.
현실감 넘치는 퀀 트레이딩 팁.

QuantStart.
빠르게 성장하는 소매점 퀀텀 트레이더 커뮤니티를 지원하는 Quantcademy 개인 회원 포털에 가입하십시오. 당신은 당신의 가장 중요한 퀀트 트레이딩 질문에 대답 할 준비가되어있는 지식이 풍부하고 마음이 맞는 퀀트 트레이더 그룹을 찾을 수 있습니다.
퀀트 트레이딩에 관한 나의 eBook을 확인해보십시오. 여기서 저는 파이썬 툴로 수익성 높은 체계적인 트레이딩 전략을 만드는 법을 가르쳐드립니다.
Python 및 R을 사용하여 시계열 분석, 기계 학습 및 베이지안 통계를 사용하는 고급 거래 전략에 관한 새로운 전자 책을 살펴보십시오.
Michael Halls-Moore (2013 년 5 월 25 일)
이제 보안 마스터 데이터베이스의 개념에 대해 설명 했으므로 실제로는 보안 마스터 데이터베이스를 구축해야합니다. 이를 위해 MySQL 데이터베이스와 Python 프로그래밍 언어의 두 가지 오픈 소스 기술을 사용합니다. 이 기사의 끝 부분에는 양적 무역 연구를 위해 추가 데이터 분석을 수행 할 수있는 완벽한 자산 보안 마스터가 있습니다.
증권 마스터 데이터베이스의 이점.
시작하기 전에 지역 증권 마스터 데이터베이스를 갖는 것이 왜 유익한지를 다시 한번 설명 할 것입니다.
속도 - 로컬 하드 디스크의 유가 증권 마스터를 사용하면 팬더와 같은 모든 데이터 응용 프로그램이 잠재 네트워크 링크에서 느린 입출력 (I / O)을 수행하지 않고도 신속하게 데이터에 액세스 할 수 있습니다. 여러 소스 - 증권 마스터는 동일한 시세 표시기에 대해 여러 데이터 소스를 직접 저장할 수 있습니다. 따라서 사용자 정의 오류 수정 코드 및 / 또는 감사 추적을 추가하여 자체 데이터베이스의 데이터를 수정할 수 있습니다. 다운 타임 - 우리가 데이터에 대한 인터넷 연결에 의존하고 있으며 공급 업체가 다운 타임을 경험하고 있다면 연구를 수행 할 수 없습니다. replication system이있는 로컬 데이터베이스는 항상 사용할 수 있습니다. 메타 데이터 - 증권 마스터를 사용하면 티커 정보에 대한 메타 데이터를 저장할 수 있습니다. 교환, 공급 업체 및 심볼 매칭 테이블을 포함시켜 데이터 소스 오류를 최소화 할 수 있습니다. 거래 - 시간이 지나면 증권 마스터는 거래 거래 상점을 포함하도록 성장할 수 있습니다. 즉, 과거 가격 결정 데이터와 동일한 데이터 환경에서 수행 한 거래에 대해 데이터 분석 쿼리를 실행하여 거래 응용 프로그램의 복잡성을 최소화 할 수 있습니다.
데이터 공급 업체에 대한 연결에 의존하는 것과 달리 데이터를 로컬로 (또는 적어도 원격 서버에) 저장하는 다른 많은 이유가 있습니다. 유가 증권 마스터는 전체 알고리즘 거래 응용 프로그램 데이터 저장소를 구성 할 템플리트를 제공합니다. 그러나이 기사의 목적을 위해 우리는 매일의 역사적인 데이터의 저장에 집중할 것입니다.
증권 마스터 데이터베이스 용 MySQL.
증권 마스터 데이터베이스를 만들고 상호 작용하기 위해 MySQL과 Python / pandas를 사용합니다. 설치 절차는 플랫폼에 따라 다르므로 각 도구 세트의 설치 세부 사항은 다루지 않을 것입니다. 그러나 소프트웨어 설치에 도움이되는 몇 가지 관련 안내서를 알려 드리겠습니다.
MySQL 설치.
MySQL을 설치하려면 적절한 플랫폼을 선택하십시오 :
Windows - Microsoft Windows에 MySQL을 설치하기위한 설치 절차를 읽으려면 MySQL 설명서를 살펴보십시오. Windows 용 다운로드 바이너리를 찾으려면이 페이지를보십시오. Mac OSX - You can download the binaries for Mac OSX at the MySQL downloads page. Alternatively, you can install MySQL via homebrew. This tutorial is useful for getting started. Linux/UNIX - You have the choice of either downloading a binary from your distribution or compiling from source. On a Debian/Ubuntu system you can type sudo apt-get install mysql-server . If you are on a RPM-based distribution such as Fedora or Cent OS, you can type yum install mysql-server . To build MySQL from the source code (brave!) please look here.
Creating a New Database and User.
Now that MySQL is installed on your system we can create a new database and a user to interact with it. You will have been prompted for a root password on installation. To log on to MySQL from the command line use the following line and then enter your password:
Once you have logged in to the MySQL you can create a new database called securities_master and then select it:
Once you create a database it is necessary to add a new user to interact with the database. While you can use the root user, it is considered bad practice from a security point of view, as it grants too many permissions and can lead to a compromised system. On a local machine this is mostly irrelevant, but in a remote production environment you will certainly need to create a user with reduced permissions. In this instance our user will be called sec_user . Remember to replace password with a secure password:
The above three lines create and authorise the user to use securities_master and apply those privileges. From now on any interaction that occurs with the database will make use of the sec_user user.
Schema Design for Equities Securities Master.
We've now installed MySQL and have configured a user with which to interact with our database. At this stage we are ready to construct the necessary tables to hold our financial data. For a simple, straightforward equities master we will create four tables:
Exchange - The exchange table lists the exchanges we wish to obtain equities pricing information from. In this instance it will almost exclusively be the New York Stock Exchange (NYSE) and the National Association of Securities Dealers Automated Quotations (NASDAQ). DataVendor - This table lists information about historical pricing data vendors. We will be using Yahoo Finance to source our end-of-day (EOD) data. By introducing this table, we make it straightforward to add more vendors if necessary, such as Google Finance. Symbol - The symbol table stores the list of ticker symbols and company information. Right now we will be avoiding issues such as differing share classes and multiple symbol names. We will cover such issues in later articles! DailyPrice - This table stores the daily pricing information for each security. It can become very large if many securities are added. Hence it is necessary to optimise it for performance.
MySQL is an extremely flexible database in that it allows you to customise how the data is stored in an underlying storage engine . The two primary contenders in MySQL are MyISAM and InnoDB . Although I won't go into the details of storage engines (of which there are many!), I will say that MyISAM is more useful for fast reading (such as querying across large amounts of price information), but it doesn't support transactions (necessary to fully rollback a multi-step operation that fails mid way through). InnoDB, while transaction safe, is slower for reads.
InnoDB also allows row-level locking when making writes, while MyISAM locks the entire table when writing to it. This can have performance issues when writing a lot of information to arbitrary points in the table (such as with UPDATE statements). This is a deep topic, so I will leave the discussion to another day!
We are going to use InnoDB as it is natively transaction safe and provides row-level locking. If we find that a table is slow to be read, we can create indexes as a first step and then change the underlying storage engine if performance is still an issue. All of our tables will use the UTF-8 character set, as we wish to support international exchanges. You can read more about UTF-8 encoding at this Wikipedia page.
Let's begin with the schema and CREATE TABLE SQL code for the exchange table. It stores the abbreviation and name of the exchange (i. e. NYSE - New York Stock Exchange) as well as the geographic location. It also supports a currency and a timezone offset from UTC. We also store a created and last updated date for our own internal purposes. Finally, we set the primary index key to be an auto-incrementing integer ID (which is sufficient to handle $2^ $ records):
Here is the schema and CREATE TABLE SQL code for the data_vendor table. It stores the name, website and support . In time we can add more useful information for the vendor, such as an API endpoint URL:
Here is the schema and CREATE TABLE SQL code for the symbol table. It contains a foreign key link to an exchange (we will only be supporting exchange-traded instruments for this article), a ticker symbol (e. g. GOOG), an instrument type ('stock' or 'index'), the name of the stock or stock market index, an equities sector and a currency.
Here is the schema and CREATE TABLE SQL code for the daily_price table. This table is where the historical pricing data is actually stored. We have prefixed the table name with daily_ as we may wish to create minute or second resolution data in separate tables at a later date for higher frequency strategies. The table contains two foreign keys - one to the data vendor and another to a symbol. This uniquely identifies the data point and allows us to store the same price data for multiple vendors in the same table. We also store a price date (i. e. the daily period over which the OHLC data is valid) and the created and last updated dates for our own purposes.
The remaining fields store the open-high-low-close and adjusted close prices. Yahoo Finance provides dividend and stock splits for us, the price of which ends up in the adj_close_price column. Notice that the datatype is decimal(19,4) . When dealing with financial data it is absolutely necessary to be precise. If we had used the float datatype we would end up with rounding errors due to the nature of how float data is stored internally. The final field stores the trading volume for the day. This uses the bigint datatype so that we don't accidentally truncate extremely high volume days.
By entering all of the above SQL commands into the MySQL command line the four necessary tables will be created.
Using Python/pandas for Securities Master Interaction.
In order to begin populating the securities master it is necessary to install Python and pandas.
Installing Python/pandas.
The modern way to install Python is to use the virtual environment tool virtualenv and the pip package manager. To install Python in this manner, the following steps must be followed:
Windows - Visit Download Python to obtain a version of Python. I recommend using the 2.7.5 version, as some software is not yet Python 3 compatible (although this is gradually changing!). Once you have Python installed you need to download setuptools. The final steps are to run easy_install pip and pip install virtualenv in your command shell. Mac OSX - The best way to install Python is to use homebrew. Then you can install Python via brew install python . The next step is to run pip install virtualenv to install virtualenv. Linux/UNIX - For a Debian/Ubuntu flavoured distribution type sudo apt-get install python-pip python-dev to install pip and the Python development libraries. Then run pip install virtualenv to globally install virtualenv.
Unfortunately, installing Python, pip and virtualenv can be tricky. You may wish to look at these more detailed threads here and here if you run into trouble.
Once virtualenv is installed you can create a new Python virtual environment in a separate directory and then install pandas (commands for a Mac OSX/UNIX environment):
The final step is to install the Python-MySQL library. On Mac OSX/UNIX flavour machines we need to run the following commands:
We're now ready to begin interacting with our MySQL database via Python and pandas.
Using an Object-Relational Mapper.
For those of you with a background in database administration and development you might be asking whether it is more sensible to make use of an Object-Relational Mapper (ORM). An ORM allows objects within a programming language to be directly mapped to tables in databases such that the program code is fully unaware of the underlying storage engine. They are not without their problems, but they can save a great deal of time. The time-saving usually comes at the expense of performance, however.
A popular ORM for Python is SQLAlchemy. It allows you to specify the database schema within Python itself and thus automatically generate the CREATE TABLE code. Since we have specifically chosen MySQL and are concerned with performance, I've opted not to use an ORM for this article.
Obtaining Listed Symbols Data.
Let's begin by obtaining all of the ticker symbols associated with the Standard & Poor's list of 500 large-cap stocks, i. e. the S&P500. Of course, this is simply an example. If you are trading from the UK and wish to use UK domestic indices, you could equally well obtain the list of FTSE100 companies traded on the London Stock Exchange (LSE).
Wikipedia conveniently lists the constituents of the S&P500. We will scrape this website using the Python lxml library and add the content directly to MySQL. Firstly make sure the library is installed:
The following code will use the lxml library and add the symbols directly to the MySQL database we created earlier. Remember to replace 'password' with your chosen password as created above:
At this stage all 500 current symbol constituents of the S&P500 index are in the database. Our next task is to actually obtain the historical data from separate sources and match it up the symbols.
Obtaining Pricing Data.
In order to obtain the historical data for the current S&P500 constituents, we must first query the database for the list of all the symbols. Once the list of symbols (along with the symbol IDs) have been returned, it is possible to call the Yahoo Finance API and download the historical pricing data for each symbol. Once we have each symbol we can insert the data into the database in turn. Here's the Python code to carry this out:
Note that there are certainly ways we can optimise this procedure. If we make use of the Python ScraPy library, for instance, we would gain high concurrency from the downloads, as ScraPy is built on the event-driven Twisted framework. At the moment each download will be carried out sequentially.
Python/Pandas Interface to Pricing Data.
Now that we've downloaded the historical pricing for all of the current S&P500 constituents we want to be able to access it within Python. The pandas library makes this extremely straightforward. Here's a script that obtains the OHLC data for Google over a certain time period from our securities master database and outputs the tail of the dataset:
The output of the script follows:
This is obviously only a simple script, but it shows how powerful having a locally-stored securities master can be. It is possible to backtest certain strategies extremely rapidly with this approach, as the I/O from the database will be significantly faster than that over an internet connection.
The next step is to automate the collection of data such that each symbol has updated OHLC data after the close of the trading day. Using a task scheduler such as Windows Task Scheduler or crontab , this process can be scripted to occur in the background. It will bring us one step closer to making a fully automated trading system.
양적 거래 시작하기?
QuantStart 목록을 구독해야하는 3 가지 이유 :
1. 퀀트 트레이딩 레슨.
계량 거래를 시작하는 데 도움이되는 힌트와 팁으로 가득한 무료 10 일간 코스에 즉시 액세스 할 수 있습니다!
2. 모든 최신 내용.
매주 나는 퀀트 스타트에서 모든 활동의 포장을 보내드릴 것입니다. 그래서 당신은 결코 다시 글을 놓치지 않을 것입니다.
현실감 넘치는 퀀 트레이딩 팁.

No comments:

Post a Comment