Skip to content

Conversation

nicoubide
Copy link

My submission for the skill set challenge

@PanPip PanPip requested a review from vlrie October 25, 2021 13:09
Copy link

@vlrie vlrie left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi Nico,

This is a good submission. You have a well-documented code, and your notebook quality is also good. However, there is a minor inconsistency with the code. It is a good touch that you added the implementations for FFT and LOWESS, but you didn't perform any research on it in the notebook.

  • Overall the code is well-commented, but in some functions, the comments disappear completely. Consistency is important.
  • All functions have fitting docstrings, but some are way better described than others. Parameters and returns are not always mentioned for the functions.
  • Good split of code into classes.
  • In the Jupyter notebook, the PNL results look a little bit too good to be true and need deeper questioning.
  • It might also be a good idea to assess the quality of chosen trades by comparing them with the market direction after the trade was made.

@PanPip, what are your thoughts?

@@ -0,0 +1,284 @@
"""
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In general, nicely commented and stylistically correct. Good work.

"""
Function generates the price trends at each timestep and
stores them in an instance attribute
:return:
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing the return statement in docstrings when :return: was specified.

positions_list.append(self.positions[security][-1])
return signal_list, positions_list

def get_last_issued_position(self, security: str) -> Position:
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You've stopped disclosing the parameters from this point on. Docstring consistency is important.

"""
Function generates the price trends at each timestep and
stores them in an instance attribute
:return:
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Return not specified in docstring where :return: is mentioned.

Comment on lines +257 to +258
:param pt:
:return:
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unspecified :param pt:and :return: in docstring

) -> np.ndarray:
"""
By MLdP on 02/22/2014 <[email protected]>
Kinetic Component Analysis
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Parameter and return description missing

return smoothed_state_means


def select_fft(series: pd.Series(), min_alpha: Optional[float] = None,) -> np.ndarray:
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great to see that you've implemented FFT and LOWESS.

"**2)** Velocity (-), Acceleration (+):\n",
"\n",
"- If velocity has a negative sign and acceleration has a positive we infer this to be a price signal that is on its way down but progressively getting slower\n",
"- This suggests that we should ***exit a short*** position (i.e. ***sell***)\n",
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To exit a short position we need to buy, not sell.

Comment on lines +260 to +261
if pt in [PriceTrend.up, PriceTrend.convex_up]:
return Signal.buy
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line is correct, but it contradicts your description in the notebook.

Comment on lines +92 to +94
abs_return = ((abs(row2) - abs(row1)) / abs(row1)) * 100
returns.append(abs_return * side)
ratios = (np.array(returns) + 100) / 100
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A very unusual way of calculating the returns.

Copy link
Contributor

@PanPip PanPip left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi Nico, 🙂

Great work, the code part is well written and documented. The chosen trading logic looks interesting.

Will set up an interview.

  • The notebook is well structured.
  • The signal generation code part is a bit too complicated, and has a leakage somewhere (abnormal PnL results in the notebook).
  • Good visualisation of the generated signals on the plots.
  • Good use of inline comments.
  • Extra points for type hints use.

@@ -0,0 +1,5 @@
matplotlib==3.2.2
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A clean requirements list 👍

Comment on lines +68 to +71
universe: pd.DataFrame,
seed: float,
lookback_period: dt.timedelta,
forecast_horizon: Optional[int] = None,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extra points for type hints 🙂

Optional parameter that specifies how far into the future we want to forecast
"""

# Historical price data for the securities in our investment universe
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good use of inline comments throughout implementations.

Comment on lines 1668 to 1853
},
"output_type": "display_data"
},
{
"data": {
"image/png": "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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see that the way signals are generated in the code should prevent information leakage, but these results look very suspicious. Ideally, more time should be spent simplifying the signal generation code to find where the issue is coming from.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants